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.