Run your Flask app on Kubernetes

In this article we are going to use a very simple Flask application, “dockerise” it and then run it on Kubernetes using minikube.

Part 1 : The basics

The files that we should have at the end of this first part will look like this :


Flask application

This is the most basic flask app. We just changed the host to listen not only on (localhost) but on all interfaces, and we enable the debug mode.

from flask import Flask
app = Flask(__name__)
def hello():
    return "Hello World!"
if __name__ == '__main__':,host='')

You can test this app by running the following command :


Result should look like :

╰─ python
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 236-626-748

Now when you browse or http://localhost:5000 you should see a blank web page with “Hello World !”


Great ! Now that we have our (very) basic Flask app we will put in a Docker container. To do so create a Docker file with the following informations :

#Dockerfile for flask_hello
FROM python:3.7
WORKDIR /usr/src/app
COPY . /usr/src/app/
RUN pip install --no-cache-dir -r requirements.txt
ENTRYPOINT ["python"]
CMD [""]

FROM python:3.7 > use the python image with version tag 3.7

WORKDIR : set the current working directory during the build

COPY : copy the content of the local current directory to the destination in the container

RUN : run the pip install comment with the requirement file as an argument (see below)

EXPOSE : as flask use port 5000 we expose this port on the container

ENTRYPOINT : is the command to run when the container starts

CMD : This will be provide a default argument to the entry point

The result will be a basic container using the official python 3.7 image with our flask code, all necessary requirement (Flask), necessary port open and flask server running at start.



The requirement file contains all necessary library for our code to be run.
I recommend using virtualenv and running the following command to populate the file :

pip freeze > requirement.txt                                                                           

The content of your file should at least contain the following (with newer version as this blog post gets old)

# requirement.txt


To avoid having unnecessary files copied to your docker container I recommend that you use a dockerignore file (similar to .gitignore file). This will exclude those files during the container build process.

# .dockerignore

Because we want to deploy our app to kubernetes we will need to push our image to a docker registry, kubernetes will later pull it when deploying the pods. You can use the registry of your choice, to keep it simple we will use dockerhub. I should therefore have a dockerhub account and configure docker on your local machine to identify using docker login command.

Now we will create the docker image. Replace <yourDockerHubName> with your docker username.

docker build -t <yourDockerHubName>/flask-hello .

-t : use tag, 
docker hub identifier : yourDockerHubName
image name : flask-hello
. : tell docker to look for dockerfile in the current directory

Output example :

╰─ docker build -t climz/flask-hello .
Sending build context to Docker daemon  9.728kB
Step 1/7 : FROM python:3.7
 ---> a4cc999cf2aa
Step 2/7 : WORKDIR /usr/src/app
 ---> Using cache
 ---> cb7ff906ed67
Step 3/7 : COPY . /usr/src/app/
 ---> 2b3760e2a13a
Step 4/7 : RUN pip install --no-cache-dir -r requirements.txt
 ---> Running in 97deac8e0f34
Collecting Flask==1.0.3 (from -r requirements.txt (line 1))
  Downloading (92kB)
Collecting Jinja2>=2.10 (from Flask==1.0.3->-r requirements.txt (line 1))
  Downloading (124kB)
Collecting Werkzeug>=0.14 (from Flask==1.0.3->-r requirements.txt (line 1))
  Downloading (327kB)
Collecting click>=5.1 (from Flask==1.0.3->-r requirements.txt (line 1))
  Downloading (81kB)
Collecting itsdangerous>=0.24 (from Flask==1.0.3->-r requirements.txt (line 1))
Collecting MarkupSafe>=0.23 (from Jinja2>=2.10->Flask==1.0.3->-r requirements.txt (line 1))
Installing collected packages: MarkupSafe, Jinja2, Werkzeug, click, itsdangerous, Flask
Successfully installed Flask-1.0.3 Jinja2-2.10.1 MarkupSafe-1.1.1 Werkzeug-0.15.4 click-7.0 itsdangerous-1.1.0
Removing intermediate container 97deac8e0f34
 ---> b3662c206b73
Step 5/7 : EXPOSE 5000
 ---> Running in 8376f2f876ec
Removing intermediate container 8376f2f876ec
 ---> c48fd492bf8c
Step 6/7 : ENTRYPOINT ["python"]
 ---> Running in b9abf653178d
Removing intermediate container b9abf653178d
 ---> 592be6581762
Step 7/7 : CMD [""]
 ---> Running in 521afc1d4139
Removing intermediate container 521afc1d4139
 ---> cfae4f0824b1
Successfully built cfae4f0824b1
Successfully tagged climz/flask-hello:latest

Because we did not specify any version tag, docker automatically tag the image with version “latest”

We can now test your docker image by creating a container on our local machine :

docker run --name flask-hello -d -p 5000:5000 climz/flask-hello:latest

View your container running

─ docker ps
CONTAINER ID        IMAGE                      COMMAND             CREATED             STATUS              PORTS                    NAMES
992b8ab307f9        climz/flask-hello:latest   "python"     6 seconds ago       Up 4 seconds>5000/tcp   flask-hello

You can test it by accessing the Flask app using the following URLs or http://localhost:5000

Now that the image is created and test we can push it to the docker hub registry.

docker image push climz/flask-hello

Kubernetes deployment

At this stage we have a basic Flask app and a docker image containing the app pushed to the docker registry.

We will now deploy it on a brand new (and empty) kubernetes cluster. Here I’m using miniukube for test purpose but running on any other k8s cluster would be the same.

We will create two k8s objects :
– a deployment : the deployment is the recommended way to deploy your app on k8s. Under the hood it will create a replica set and the necessary pods.
– a service : it will expose our application.

Deployment definition

# deployment.yaml - Flask hello world deployment
apiVersion: apps/v1
kind: Deployment
  name: flask-hello-deployment
    app: flask-hello
  replicas: 2
      app: flask-hello
        app: flask-hello
      - name: flask-hello
        image: climz/flask-hello:latest
        - containerPort: 5000

Service definition

# service.yaml Flask hello world service
apiVersion: v1
kind: Service
  name: my-service
    app: flask-hello
  - protocol: TCP
    port: 8080
    targetPort: 5000
  type: NodePort

Note : you can also put both deployment and service in the same file separate by ---

Deploy to kubernetes

kubectl create deployment.yaml
kubectl create service.yaml


kubectl create -f .


kubectl diff -f .
kubectl apply -f .

To retrieve the IP address you need to use to access your application run the following command :

minikube service my-service --url

The port (NodePort:) on your kubernetes cluster IP is automatically assigned on a range between (30000-32767)

Hello World! Welcome to the great world of flask.

You should now be able to access the application

To get logs

kubectl logs -f -lapp=flask-hello

Part 2 : Improvements

makefile : coming soon

Jenkins pipeline : coming soon

Production server : coming soon

Leave a Reply

Your email address will not be published. Required fields are marked *