Deploy a Flask App with Docker

I wanted to understand how to host a simple Flask app inside a Docker container, so I went through the following exercise. In the future, I would use something more like the tiangolo/uwsgi-nginx-flask docker image.

Installation

First, install the Docker using their installation instructions for you platform. I am on a mac, so I installed the DMG from their site, and then from the command line ran,

brew install docker

The Docker daemon doesn’t start automatically after downloading it, so you need to find it, and double-click on it to start it up. Once it’s running, you can execute docker commands from the command line.

Setup

Create and cd into a directory called example/.

mkdir example
cd example

Creating a Simple Flask App

I made a simple Flask app to respond with “Hallo, Welt” whenever I perform a GET request on port 8000. I called this app.py, and put it in a directory called app/ in the example/ directory.

#!/usr/local/bin/python3
# ~/example/app/app.py

from flask import Flask

app = Flask(__name__)


@app.route("/")
def index():
    return "Hallo, Welt"


if __name__ == '__main__':
    app.debug = True
    app.run(host='0.0.0.0', port=8000)

Make sure you specify the host as '0.0.0.0', otherwise you will not be able to access your app outside of your container.

Start a Virtual Environment on your Host

Creating a virtual environment for your application will help you install and import only what is needed for your application. Once it is time to deploy, just freeze your requirements into a requirements.txt document, and you’ll have a snapshot of what your application needs in order to run.

If you’re using Python3, from the example/ directory you can say,

python3 -m venv venv
source venv/bin/activate

Now you should see a venv/ directory inside your example/ directory. Now install Flask by saying,

python -m pip install flask

Once that is done, create a requirements document,

pip freeze > requirements.txt

This should create requirements.txt at the root of the example/ directory.

Create a Dockerfile

I created a Dockerfile to install the requirements, copy the application over, and start the server. Note, I am currently in a directory called “example”. My Dockerfile is in the root of that directory. The app/ directory, containing my Flask app, app.py, is also in the “example” directory, beside the Dockerfile.

# ~/example/Dockerfile

FROM python:3.7.0-alpine3.8

WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install -r requirements.txt
COPY app/* .

EXPOSE 8000
CMD ["python3", "app.py"]

Build and Run Docker

Now, we should be able to build an image by saying:

docker build -t hello-world

And then we should be able to run that image in a container by saying:

docker run -p 8000:8000 hello-world

Now, if we curl the localhost on port 8000, then we should see “Hallo, Welt”

curl localhost:8000
Hallo, Welt%

Getting Fancy/Lazy in Development

Right now, each time you want to see the effect of an edit, you need to re-build and re-run docker. However, if you mount your local working directory as a volume in the container, then you can see your changes reflected in the container, as you work on things in your local directory. To do this, pass your working directory to the container using the -v option, for volume:

docker run -p 8000:8000 /Users/cjohnson/example/app:/usr/src/app hello-world

Note, it’s important to use a full path to your working directory. Relative paths, and using a tilde to represent the home directory will not work.