Flask Website Deployment using Docker Compose on Azure Cloud

In this blog, I will deploy FLASK app on nginx using Docker Compose. If you don’t have any idea how Docker Compose works, read my previous blog first (Click here to read the previous blog).
Before we move to work, I will give you brief intro the things which I am going to use. I created a virtual machine on Azure Cloud Platform. If you don’t know, how to create virtual machine on Azure, go to my this blog create virtual machine easily with few simple steps (Click here to read the blog).
After creating virtual machine just ssh into your machine using simple command.

ssh halcyoona@40.114.31.5

Installation

To install Docker the in your virtual machine, type the command in terminal and press enter:

sudo apt install docker.io
sudo apt install docker-compose

Create a directory with the name of your app, like I am creating my_flask_app.

mkdir my_flask_app
cd my_flask_app

In this floder create two more directory with the nginx and flask. Nginx is entry point of the app, where we get request and then we redirect those request to flask app.

mkdir flask
mkdir nginx

Flask App Setting

Now move into flask directory and create python virtual environment but first install package that is required to create the virtual environment i.e venv first then create virtual environment using following command:

cd flask
sudo apt install python3-venv
python3 -m venv env

Now activate the environment with the simple command:

soure env/bin/activate

And then install flask and uwsgi.

pip install flask uwsgi

flask package is used to create the applications.
uwsgi is a Web Server Gateway Interface used to communicate to nginx server.

Check the packages installed in the environment.

pip list

Output will be this:

click (7.1.2)
Flask (1.1.2)
itsdangerous (1.1.0)
Jinja2 (2.11.2)
MarkupSafe (1.1.1)
pip (9.0.1)
pkg-resources (0.0.0)
setuptools (39.0.1)
uWSGI (2.0.19.1)
Werkzeug (1.0.1)

Now create the file with name run.py and write this code into this file. This is the file which run your application.

touch run.py

And then write this code

from app import app
if __name__ == "__main__":
    app.run()

Now create the directory with the name app and inside it create two files with the name __init__.py and views.py

mkdir app
cd app
touch __init__.py
touch views.py

In __init__.py, write this code.

from flask import Flask
app = Flask(__name__)
from app import views

__init__.py is the file which runs first when your application starts.

In views.py. Write your code but I am creating simple helloworld.

from app import app
@app.route("/")
def index():
    return "Hello from Flask App"

views.py is the file in which you wrtie code for application i.e you make different pages and include those pages to views… etc.

Now we need create the requirements file which contains all the packages that is installed in the environment. Because we don’t want to write every command in Dockerfile and sometimes we forget packages and this make trouble as well.
just run this command and get requirements and include this file in Dockerfile and that’s it and all your packages will be install. First move to back to your flask directory Because we are in /flask/app.

cd ..
pip freeze > requirements.txt

Now create .dockerignor file to specify the things which you want docker to be ignor and don’t not include those in things in container.

touch .dockerignor

And write this code in this file.

env/
__pycache__/

Now move to the most important file that is Dockerfile create the Dockerfile.

touch Dockerfile

And write the following code inside the Dockerfile.


#Use the python3.7.2 image and create the container with that image.
FROM python:3.7.2-stretch

#Set the working Directory in the container
WORKDIR /app

#copy the current directory contents into container at /app. In this '.' means current directory content and move to /app in the container
ADD . /app

#Install the dependencies in the container
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
RUN pip install uWSGI

#Run the command to start uWSGI in the container
CMD ["uwsgi", "app.ini"]

You can easily get what is written in the file with comments.

Now create the file app.ini inside the flask directory and app.ini file is configuration file and you can check different configuration on uWSGI site.

cd flask
touch app.ini

And write this code in this file.

[uwsgi]
wsgi-file = run.py
callable = app
socket = :8000
processes = 4
threads = 2
master = true 
chmod-socket = 660
vacuum = true 
die-on-term = true

wsgi-file= run.py -> we have to specify the file which is used to run the application.
callable= app -> we have callable app in run.py so that’s why we use app as callable.
socket= :8000 -> This is listening on port 8000 from any IP address.

Nginx Setting

Now move to nginx directory. And create the nginx.conf. This contains the configuration setting for nginx.

touch nginx.conf

Write this code in this file.

server {
    listen 80;

    location / {
        include uwsgi_params;
        uwsgi_pass flask:8000;
    }
}

This server is listening on port 80. Actually we are redirecting request to flask using uwsgi_params. And you can see we use port 8000 to communicate Because in uwsgi configuration file we use port 8000.
Docker Compose create a network and made it very easy to communicate with different containers in the network and you should set the host name of the container to the name of your service and then this make it more easy.
As in the above we called flask container which is listening on port 8000. Because flask is host name of the container we are going to define in later in docker-compose.yml.

Now create the Dockerfile for nginx.

touch Dockerfile

And write this code in this file.

#Use the nginx Image and create the container from the Image
FROM nginx

#Remove the default nginx.conf
RUN rm /etc/nginx/conf.d/default.conf

#Replace with our own nginx.conf
COPY nginx.conf /etc/nginx/conf.d/

Docker Compose Setting

Now move to my_flask_app directory. And create the file docker-compose.yml.

touch docker-compose.yml

And write this code in it.


version: "2.2"

services:

  flask:
    build: ./flask
    container_name: flask
    restart: always
    environment: 
      - APP_NAME=MyFlaskApp
      - DB_USERNAME=example
    expose:
      - 8000
  
  nginx:
    build: ./nginx
    container_name: nginx
    restart: always
    ports:
      - "80:80"

build:./flask -> This is actually looking for a flask directory in the current directory and then run the Dockerfile inside the flask directory.
container_name: flask -> assigning host name to the container.
expose: 8000 -> Exposing port 8000 to other containers.
ports: “80:80” -> mapping host operating system port to containers port. The request comes to over virtual machine on port 80 goes to the nginx container port 80 and then nginx redirect it to flask container.

Running Docker Compose

Now every thing is complete and move to build.

sudo docker-compose build

It’s good to watch the output which packages are installing.


Building flask
Step 1/7 : FROM python:3.7.2-stretch
3.7.2-stretch: Pulling from library/python
e79bb959ec00: Pull complete
d4b7902036fe: Pull complete
1b2a72d4e030: Pull complete
d54db43011fd: Pull complete
69d473365bb3: Pull complete
7dc3a6a0e509: Pull complete
a288a79001c3: Pull complete
7d3cdae56021: Pull complete
dbf17696f820: Pull complete
Digest: sha256:a67ce4c774591f13500901fd4061e0c96a274c1e88fa8f6a96efaa983ae9c203
Status: Downloaded newer image for python:3.7.2-stretch
Step 2/7 : WORKDIR /app
 ---> Using cache
 ---> a2c58f6f2a90
Step 3/7 : ADD . /app
 ---> 59ff085f8e6c
Step 4/7 : RUN pip install --upgrade pip
 ---> Running in 12544c84d3f7
Collecting pip
  Downloading https://files.pythonhosted.org/packages/43/84/23ed6a1796480a6f1a2d38f2802901d078266bda38388954d01d3f2e821d/pip-20.1.1-py2.py3-none-any.whl (1.5MB)
Installing collected packages: pip
  Found existing installation: pip 19.0.3
    Uninstalling pip-19.0.3:
      Successfully uninstalled pip-19.0.3
Successfully installed pip-20.1.1
Removing intermediate container 12544c84d3f7
 ---> 88502a46901b
Step 5/7 : RUN pip install -r requirements.txt
 ---> Running in 917442f8ebf3
Collecting click==7.1.2
  Downloading click-7.1.2-py2.py3-none-any.whl (82 kB)
Collecting Flask==1.1.2
  Downloading Flask-1.1.2-py2.py3-none-any.whl (94 kB)
Collecting itsdangerous==1.1.0
  Downloading itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB)
Collecting Jinja2==2.11.2
  Downloading Jinja2-2.11.2-py2.py3-none-any.whl (125 kB)
Collecting MarkupSafe==1.1.1
  Downloading MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl (27 kB)
Collecting Werkzeug==1.0.1
  Downloading Werkzeug-1.0.1-py2.py3-none-any.whl (298 kB)
Installing collected packages: click, Werkzeug, MarkupSafe, Jinja2, itsdangerous, Flask
Successfully installed Flask-1.1.2 Jinja2-2.11.2 MarkupSafe-1.1.1 Werkzeug-1.0.1 click-7.1.2 itsdangerous-1.1.0
Removing intermediate container 917442f8ebf3
 ---> bc5156d8e278
Step 6/7 : RUN pip install uWSGI
 ---> Running in 4a028bae390c
Collecting uWSGI
  Downloading uWSGI-2.0.19.1.tar.gz (803 kB)
Building wheels for collected packages: uWSGI
  Building wheel for uWSGI (setup.py): started
  Building wheel for uWSGI (setup.py): finished with status 'done'
  Created wheel for uWSGI: filename=uWSGI-2.0.19.1-cp37-cp37m-linux_x86_64.whl size=595659 sha256=89886458bfd5a67dd2693f4d1e3a56917c494f8f237f0393c4994d62316ecede
  Stored in directory: /root/.cache/pip/wheels/0c/f9/df/fb7fb12204a8f5c67682f31e10485863c24123a2a626e71203
Successfully built uWSGI
Installing collected packages: uWSGI
Successfully installed uWSGI-2.0.19.1
Removing intermediate container 4a028bae390c
 ---> 1ed5b7818c52
Step 7/7 : CMD ["uwsgi", "app.ini"]
 ---> Running in b6683d9e1ce3
Removing intermediate container b6683d9e1ce3
 ---> a749b9c5fab8
Successfully built a749b9c5fab8
Successfully tagged myflaskapp_flask:latest
Building nginx
Step 1/3 : FROM nginx
latest: Pulling from library/nginx
8559a31e96f4: Pull complete
1cf27aa8120b: Pull complete
67d252a8c1e1: Pull complete
9c2b660fcff6: Pull complete
4584011f2cd1: Pull complete
Digest: sha256:a93c8a0b0974c967aebe868a186e5c205f4d3bcb5423a56559f2f9599074bbcd
Status: Downloaded newer image for nginx:latest
 ---> 0901fa9da894
Step 2/3 : RUN rm /etc/nginx/conf.d/default.conf
 ---> Running in bba46218a4e2
Removing intermediate container bba46218a4e2
 ---> 9249b1579938
Step 3/3 : COPY nginx.conf /etc/nginx/conf.d/
 ---> 7746a1467014
Successfully built 7746a1467014
Successfully tagged myflaskapp_nginx:latest

This will build the containers and set the environment. And you can see every step that Docker Compose takes.

Now Run the environment.

sudo docker-compose up

Now open the browser on any machine access the IP address of your virtual machine you will get this on your browser.

That’s it for now. In next blog I am going to add database in this project making link between database and flask.

One thought on “Flask Website Deployment using Docker Compose on Azure Cloud

Leave a comment