A while ago I wrote a post about how to serve a Flask application on a webserver. Today I want to write about how to achieve this by using a docker container. Using a container for deploying web applications has the main advantage of shipping an isolated environment in a Black Box to its destination. So you don' t depend on the server operating system or the configuration. You don' t have to worry about the right version of Python being installed and so on. Also the whole shipping mechanism via Docker Hub works great. So let' s get moving.

Flask Boilerplate

We will use a flask boilerplate I created for getting a Flask Webapp working really fast.

$ git clone https://github.com/MrLeeh/flask-boilerplate.git

After cloning the application create a new virtual environment, install all dependencies and make a testrun.

$ virtualenv venv
...
$ source venv/bin/activate
(venv) $ pip install -r requirements/production.txt
...
(venv) $ python manage.py runserver
...

When opening http://localhost:5000 with your browser you should see the Flask-Boilerplate info page looking like this:

flask-boilerplate-big

Creating the Dockerfile

We want to create a container that includes the whole web application. The WSGI application shall be served by a gunicorn application server. To relief the WSGI server from serving static files (like the Tardis on the index page) we want to put a nginx proxy server in our container as well. So we create a new file called Dockerfile.

Dockerfile

FROM debian:latest
RUN apt-get update -y
RUN apt-get install -y python3-pip python3-dev build-essential
RUN apt-get install -y nginx
COPY . /app
COPY webapp.conf /etc/nginx/sites-available/webapp.conf
RUN ln -s /etc/nginx/sites-available/webapp.conf /etc/nginx/sites-enabled
RUN rm /etc/nginx/sites-enabled/default
WORKDIR /app
EXPOSE 80
RUN pip3 install -r requirements/production.txt
CMD /app/start.sh

The syntax of a Dockerfile can be found at the official Dockerfile Reference. What we actually do here is using the latest debian container as a platform. We install python3, pip and nginx and copy the content of our web-app to the /app directory. Also we copy a file called webapp.conf to the nginx config directory. We will deal with this file later. In the line next-to-last we install all necessary Python packages listed in our requirements file and finally the last line runs our small startup script.

The nginx configuration file

This file tells our nginx server what to do with the incoming requests. We still need to create it.

webapp.conf

server {
    listen 80;

    location /{
        proxy_pass http://localhost:5000;
    }

    location /static/ {
        alias /app/app/static/;
    }
}

This actually tells nginx to pass all requests from port 80 to our WSGI application server which listens on port 5000. The only exception are static files which we will serve directly from /app/app/static/.

The startup script

Actually it is not easily possible to run multiple commands on container-startup. So we need to write a small script that starts our nginx server and the gunicorn WSGI server.

start.sh

#! /bin/bash
service nginx start
gunicorn wsgi:application -b0.0.0.0:5000

Build and run the container

Now we can build our container and run it.

$ docker build flasktest .
$ docker run -d -p8080:80 flasktest

So if you open up http://localhost:8080 in your browser you should see the Tardis again.