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:
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.