So I’ve been taking some time to look into Kubernetes. One of the first things I wanted to try was to write my own simple application that uses Docker and Kubernetes locally. When I attempted to do that, it wasn’t obvious how, and furthermore, I noticed that it didn’t seem like there was a straightforward tutorial that walked you through the steps of how to launch a simple local web application from code that you have specifically written and have it running inside Kubernetes. On starting, it wasn’t obvious how to connect all the dots.
If you find yourself in a similar position then hopefully I give some insight into how to run a local, self-written, web application on Kubernetes.
Running Local ‘netes
First off, in order to run Kubernetes on your local machine there are a few options you can go with. I’ll just cover two here: Minikube and Docker’s built-in Kubernetes cluster.
If you want to use Minikube, download it at this link:
Once you have it installed it, just run
After this we need to grab the IP for Minikube, so just run
minikube ip and you should see the IP address printed out, similar to:
After this if we want our Kubernetes cluster to be able to read our local Docker images, we must first run:
eval $(minikube docker-env)
To use Docker Desktop’s built-in local cluster, first you’ll want to download it here:
After downloading it, open Preferences, go into the Kubernetes menu, and select Enable Kubernetes. You won’t need to grab a specific IP like with Minikube, instead you’ll just use
Docker Desktop comes with another tool we’ll be using:
kubectl. If for some reason it was not installed, grab it here:
Our Python App and the Docker Container
For our web application, we’ll be using the Python Flask framework. Our main application code (simple though it is) is in a file named
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello ‘netes!' if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=int("5000"))
With the Python web application piece taken care of, we need to look at the Docker container. We’re going to make a file named
Dockerfile in the same directory as the Python application. Our
Dockerfile is similarly (and intentionally) very simple:
FROM python:alpine3.7 ADD app.py / RUN pip install Flask EXPOSE 5000 CMD [ "python", "./app.py"]
With that we just run:
docker build -t simple-flask-app .
The Good Part (the Kubernetes Part)
Next we need to write the Kubernetes YAML file for deployment. We’ll call it
apiVersion: apps/v1 kind: Deployment metadata: name: simple-flask-app labels: app: simple-flask-app spec: replicas: 1 selector: matchLabels: app: simple-flask-app template: metadata: labels: app: simple-flask-app spec: containers: - name: simple-flask-app image: simple-flask-app imagePullPolicy: IfNotPresent
For a description of what each property in the YAML file does this post does a good job explaining it:
One thing I do want to point out is that in order to use the image from our local repository, I had to add the property
imagePullPolicy, and set it to
IfNotPresent, so that Kubernetes defaults to pulling from your local repository vs. some remote location.
With the YAML file set up, from the same directory we run:
kubectl create -f simple-app-deployment.yml
Now if you run
kubectl get all, the output should look something like this:
NAME READY STATUS RESTARTS AGE pod/simple-flask-app-5d77cf8454-lkfzk 1/1 Running 0 41s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13d NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/simple-flask-app 1/1 1 1 41s NAME DESIRED CURRENT READY AGE replicaset.apps/simple-flask-app-5d77cf8454 1 1 1 41s
From the above we know that the cluster is running. However, we still need to be able to connect to the app to see our wonderful
Hello ‘netes message. In order do that we’re going to expose it via a service.
We can do this by running:
kubectl expose deployment simple-flask-app --type=NodePort --port 5000
When we run
kubectl get all again the output should now look like this:
NAME READY STATUS RESTARTS AGE pod/simple-flask-app-5d77cf8454-lkfzk 1/1 Running 0 6m17s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13d service/simple-flask-app NodePort 10.103.183.40 <none> 5000:32280/TCP 58s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/simple-flask-app 1/1 1 1 6m17s NAME DESIRED CURRENT READY AGE replicaset.apps/simple-flask-app-5d77cf8454 1 1 1 6m17s
With that, let’s use the IP we obtained above and the port exposed in our
simple-flask-app service (in the example above it would be port
32280) to format our URL. Then let’s hit it with
curl to test if we can see our message:
curl http://192.168.64.2:32280/ Hello ‘netes!
So with that our simple Python Kubernetes Docker application is up and running!
In order to clean up everything locally, just run:
kubectl delete deployment simple-flask-app kubectl delete service simple-flask-app
So it’s pretty trivial to create a trival web application and tie it to Kubernetes locally. This is, of course, not nearly the same as getting a real cluster up and running. But hopefully this can help you get a quick and dirty look at getting a Python application up and running using Kubernetes and Docker.
If you want to just take a look at the code, all the files for this application are here: