Launching Flask with Docker
This article while hopefully useful, does not contain information that is not already on the internet. In fact I learnt most of what’s in this article from the internet thanks to other generous folks. But I didn’t find all the information in one place so I thought I would write this and it could possibly save some people a little time.
This article is going to walk through how to run a flask app in a docker container that you can see on your browser.
Setting up Docker:
I followed the instructions on the docker website to setup docker desktop for my mac and similarly on Ubuntu. Once you have docker setup, we can get started.
We will need a terminal to run our docker commands. I personally prefer using iTerm2 or the terminal in visual studio code.
There are 2 files that are needed for this. The Dockerfile and the python script (app.py). They will need to be in the same directory for this example.
First the Dockerfile. The file name is usually Dockerfile
. It can be named anything but for this example we will go with Dockerfile
. If you decide to name it something else (say flask.dockerfile
), I will add how to use it that as well.
Dockerfile:
# Example of Dockerfile
FROM python:3.8.5-alpine3.12
WORKDIR /app
EXPOSE 5001
RUN pip install flask
python:3.8.5-alpine3.12
is the base image from which we build on top of.
WORKDIR /app
specifies the workdir which is where the Docker container begins from. So everything will be relative to this directory.
EXPOSE 5001
specifies which port to be made available outside the docker container.
RUN pip install flask
installs flask package that we will be using.
While we are using flask here, the previous line is how we expose any port from the container for any application.
app.py
The app.py is the python code that spins up and the server and returns back a url that we can see in our browser. In this code, it will just print Hello world
# app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return "Hello world"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5001)
Now that you have the code, time to run it.
First we will need to build our docker image. To do so we run from our directory (in the terminal)
docker build . -t deploy_flask
Output:
[+] Building 7.1s (7/7) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 142B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/python:3.8.5-alpine3.12 2.4s
=> [1/3] FROM docker.io/library/python:3.8.5-alpine3.12@sha256:cbc08bfc4b1b732076742f52852ede090e960ab7470d0a60ee4f964cfa7c710a 0.0s
=> CACHED [2/3] WORKDIR /app 0.0s
=> [3/3] RUN pip install flask 4.4s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:df3a8f348e906648a269be724cc9010a50f73e06b0f5f4c1baa774c8d5543b39 0.0s
=> => naming to docker.io/library/deploy_flask 0.0s
Now if you instead decided to not name the Dockerfile as is and named it something else (say flask.dockerfile), the command will instead be:
docker build -f flask.dockerfile . -t deploy_flask
To launch the container which will run your python code we call from the same place we built our docker image
docker run -p 5001:5001 -t -i -v "$(pwd)"/.:/app deploy_flask:latest python3 app.py
Output:
* Serving Flask app 'app'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5001
* Running on http://172.17.0.2:5001
Press CTRL+C to quit
And on the browser you will see (Use the first url: http://127.0.0.1:5001
):
Now I’ve done something a little differently here than other tutorials you would see (including the Bing Chat example below). In this run command I mount the volume where the code lives rather than copying it into the container and deploying it from within. This is mainly because, I am doing this from the view point of a developer who probably wants to make changes to their code without needing to rebuild the image every time.
So to break down this command:
docker run
tells that we are going to run a command in a new docker container.-p 5001:5001
maps the port we exposed to the port we will use. For simplicity I usually keep them the same though you don’t have to.-t -i
are commands I use so that we can interact with the script and pass inputs to it.-v "$(pwd)"/.:/app
mounts the specified directory as the/app
directory within the container. If you remember from above we specified/app
as the workdir in our Dockerfile script.deploy_flask:latest
is the image we want to use. From our docker build command we named our imagedeploy_flask.
We wish to use the latest version of it by specifying latest.python3 app.py
is us launching the python script we wrote above.
Here is the official documentation from docker and mapped to our run command.
Docker documentation:
docker run - Run a command in a new container
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
OPTIONS:
-p - Publish a container's port(s) to the host
-i - Keep STDIN open even if not attached
-t - Allocate a pseudo-TTY
-v - Bind mount a volume
IMAGE:
deploy_flask:latest
COMMAND:
python3
ARG:
app.py
I’m sure many of you wonder, is this written by ChatGPT. Well I asked this prompt to Bing chat:
write a code example of running flask from a docker container including the Dockerfile
and the response is pretty close to what I have here:
Sure! Here’s an example of a simple Flask app running in a Docker container. First, you’ll need to create a file named Dockerfile
with the following content:
FROM python:3.7
WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 5000
CMD ["python", "app.py"]
This Dockerfile
specifies that the base image should be python:3.7
, sets the working directory to /app
, copies the current directory into the container at /app
, installs the dependencies specified in requirements.txt
, exposes port 5000
, and runs app.py
using Python when the container starts.
You’ll also need a file named requirements.txt
that specifies the dependencies for your Flask app. For example:
Flask==1.1.2
Finally, you’ll need a file named app.py
that contains your Flask app. Here’s an example:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run(host='0.0.0.0')
Once you have these three files, you can build and run your Docker container with the following commands:
docker build -t my-flask-app .
docker run -p 5000:5000 my-flask-app
This will build a Docker image named my-flask-app
using the Dockerfile
and then run a container from that image, mapping port 5000
on your host machine to port 5000
in the container.
After running these commands, you should be able to access your Flask app by visiting
http://localhost:5000
in your web browser.
So it essentially does as good a job as me in writing this up. I would be lying if I said I didn’t look at what Bing provided and updated my post. But here’s a fun poll for those who got all the way here: