Production ready containerization of your flask application using Docker

Preetam Keshari Nahak
3 min readJun 13, 2021

--

In this article, I will be explaining the step by step process to dockerize a production-ready simple flask application and how to implement gitlab CI on top of it for smooth integration flow.

Our flask application contains a simple endpoint /apis/time which will fetch the current time. Link to the demo application is given at the end of this article. As we are going to make it production ready, we will have to use a production-quality WSGI server. So we will be using waitress for this. There are other production quality WSGI servers available there e.g. gunicorn which you can use also. So assuming we have a simple flask application set up, let’s dive in to know about how to dockerize it.

A. Write your Dockerfile:
On the root directory of your application, create Dockerfile and a .py file which serves the application using waitress. In our case, it is wsgi.py. Now add the following contents into your Dockerfile.

FROM python:alpine3.7
COPY . /app
WORKDIR /app
RUN pip install pipenv && pipenv install --deploy --ignore-pipfile
EXPOSE 5000
CMD ["pipenv", "run" ,"python", "/app/wsgi.py", "0.0.0.0:5000" ]

Let’s try understand each line of this file one by one.

  • In the first line, we are pulling an alpine image with python 3.7 in it. Alpine a small, resource efficient, Linux based lightweight OS.
  • Next, we are copying all of the application content to /app directory and then in the 3rd line we are setting up the working directory to /app, so that whatever commands we run will be run in this directory only.
  • In the 4th line, we are installing pipenv which is python package manager module. Then using this module we are installing all the required dependency and modules.
  • In the next line, we have exposed port 5000 of the container because we will run our wsgi server on port 5000 inside the container.
  • In the last line, we define the command which will run when the container starts. The command mentioned there basically fires up the waitress server on port 5000.

So this is how your dockerfile will look like. Now you can build a docker image out of it locally and use it wherever required or setup a ci-cd pipeline using Jenkins/gitlab ci/GitHub runner to automate the whole process of building docker artifacts. Here we will setup a gitlab ci pipeline assuming you are using gitlab for code and version management.

B. Setup a gitlab ci pipeline
In order to setup the pipeline, create a .gitlab-ci.yml file in the root directory of your application. Add the following content to the file. (Note: You can use your own convention of tagging the docker images and branches to look for while building the images).

stages:
- docker build
docker build:
stage: docker build
image: docker:stable
services:
- docker:dind
before_script:
- docker info
- docker login registry.gitlab.com -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD}
script:
- docker build -t ${CI_REGISTRY}/${CI_PROJECT_PATH}:${CI_COMMIT_REF_NAME} .
- docker push ${CI_REGISTRY}/${CI_PROJECT_PATH}:${CI_COMMIT_REF_NAME}
after_script:
- docker logout ${CI_REGISTRY}
only:
- master
- /^RELEASE_[0-9]+(?:.[0-9]+)+$/
tags: ["docker"]

More details about the syntax of a .gitlab-ci.yml file is discussed in this article.

So as soon as we push any changes to maser or any other branch with prefix RELEASE, the script will run in the gitlab runner and build a docker image for us. It will appropriately tag the built images as described in the above file and store these artifacts in the gitlab registry. Hence we can pull the image wherever we want and get our production ready flask application up and running. Below is the gitlab repository link to the sample flask application the article is based upon.

Hope you found this article useful.

--

--

Preetam Keshari Nahak

Technology Enthusiast | Software Engineer | Distributed Systems