Containerizing Python Web Application
Let’s start building something awesome.
Srinaveen Desu
In this article, we will try to build a ‘hello world’ web application and containerize the web application using docker. Why containerize? I am pretty sure there would be hundreds of articles explaining the why part in detail, but let me also give a few lines on the same.
They allow us to build a software application that can be run independently of the computing environment. Thus allowing us to concentrate more on the software and less on the underlying infrastructure.
The container can be thought like a box that has the software solution, its dependencies, and libraries, binaries, and the corresponding configuration files which can be run as a single unit.
This is containerization in a nutshell, but you could browse through the web to understand the underlying essence of it in detail. In this article, we would learn to build a basic container and deploy our ‘Hello world’ python app on the container.
Before you go any further, make sure you install docker and Python3.
Let’s start building something awesome.
Start by creating a directory, sub-directories, and files similar to below structure
$ mkdir learner_project$ mkdir learner_project/app$ touch learner_project/app/app.py$ touch learner_project/app/requirements.txt$ touch Dockerfile|-- Dockerfile
|-- app
| |-- app.py
| |-- requirements.txt
|-- static
`-- templates
The folder structure I have here is a typical python flask application structure. You could have it any way you like, but I like to keep things organized as per standards. You could ignore the directories static
and templates
for now.
I think with this you have set up a blueprint for your application and all you need now is to build the solution. Please note that we would not be writing more code in this article. The goal is to learn to containerize our application.
The contents of app.py
look the following:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World! How are you doing?'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8008, debug=True)
The contents of the file requirements.txt
are :
flask
That’s it and you are ready to run your python web application. When I run the application I see the following(I installed the flask
library prior to execution):
$ python app/app.py
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
* Running on http://0.0.0.0:8008/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 961-117-870
What does this mean? Your web application is running and listening on localhost:8008
. When you hit the URL in the browser you should see the following message
Hello World! How are you doing?
If you have come so far that means you can pat your back. You have built your web application. So far we were building the application on our machine and all the application modules exist in our machine only. Now, if anyone wants to run this application you would have to give all the steps that you had done so far, in order for them to successfully execute the app.
Instead when we containerize our application we would be able to just give the container image and anyone could run a container from this image with a simple command and voila the application would be running as it were on our machine.
For this, we would have to define the Dockerfile
which would be having a list of instructions to build an image from which a container could be brought up and then the application can be run on anyone's machine using this image.
FROM python:3.8-alpine
MAINTAINER Srinaveen Desu
COPY ./app/requirements.txt /app/requirements.txt
WORKDIR /app
RUN apk add --update \
&& pip install --upgrade pip \
&& pip install -r requirements.txt \
&& rm -rf /var/cache/apk/*
COPY ./app /app
CMD python app.py
The instruction FROM
tells the image on which our application would be running and in this case, it is python
followed by version tag 3.8-alpine
.
The instruction MAINTAINER
(optional) tells who is currently moderating this Dockerfile.
The instruction COPY
tells the file that needs to be copied from your local machine to the Docker container. (source to destination)
The instruction RUN
executes the commands which are responsible for setting up the required environment for our application to run and these get added into the image we would be building.
The instruction CMD
is a command which is run once our container starts. A typical use case would be starting the web application server.
Now that our Dockerfile is ready, we are ready to build the image and run the container. The command is run in the directory where Dockerfile
exists. It builds the image flask-demo-container
which is versioned 1.0
$ pwd
/Users/desu/learner_project$ docker build --tag flask-demo-container:1.0 .Sending build context to Docker daemon 9.047MBStep 1/7 : FROM python:3.8-alpine---> 44fceb565b2aStep 2/7 : MAINTAINER Srinaveen Desu---> Using cache---> 81c543f544caStep 3/7 : COPY ./app/requirements.txt /app/requirements.txt---> Using cache---> 7446b6ed7a69Step 4/7 : WORKDIR /app---> Using cache---> 76a94dbf8407Step 5/7 : RUN apk add --update && pip install --upgrade pip && pip install -r requirements.txt && rm -rf /var/cache/apk/*---> Using cache---> bda14c8083c5Step 6/7 : COPY ./app /app---> a5f384727c69Step 7/7 : CMD python app.py---> Running in dc00695397f9Removing intermediate container dc00695397f9---> 853572c38b75Successfully built 853572c38b75Successfully tagged flask-demo-container:1.0
If you see the two successful messages you are good to go to the next step which is running the container.
$ docker run --publish 8000:8008 --name flask-demo-app flask-demo-container:1.0* Serving Flask app "app" (lazy loading)* Environment: productionWARNING: This is a development server. Do not use it in a production deployment.Use a production WSGI server instead.* Debug mode: on* Running on http://0.0.0.0:8008/ (Press CTRL+C to quit)* Restarting with stat* Debugger is active!* Debugger PIN: 185-072-509172.17.0.1 - - [01/Sep/2020 06:03:47] "GET / HTTP/1.1" 200 -
If we hit the URL
localhost:8000 you would see the hello world
message you had seen earlier.
--publish
forwards traffic hit at the port 8000
of the local machine to the port 8008
of the container.
--name
is the unique name that you give to the container.
And the last part of the command is the image followed by the version that we want the container to be run from.
If we want to run the container in the detached mode(running the container in the background) you would have to use the following command:
$ docker run --detach -p 8004:8008 --name flask-demo-app flask-demo-container:1.1
Note1: I have changed the image version to 1.1
Note2: In case you want to stop the container (in the case of detached mode) you would have to run the following command
docker stop <container-name>
In case you want to run the container again, you would have to remove the container before issuing the run command given above.
docker rm <container-name>
That was all for this article. Hope you had some fun learning cool stuff :).
References: Docker Doc
Upvote
Srinaveen Desu
A pythonista by nature. I like learning new technologies and building innovative solutions out of it.

Related Articles