Categories
Uncategorized

The Simplest Local Kubernetes Web Application Setup

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.

Minikube

If you want to use Minikube, download it at this link:

https://kubernetes.io/docs/tasks/tools/install-minikube/

Once you have it installed it, just run minikube start.

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:

192.168.64.2

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)

Docker

To use Docker Desktop’s built-in local cluster, first you’ll want to download it here:

https://docs.docker.com/desktop/

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 localhost.

Docker Desktop comes with another tool we’ll be using: kubectl. If for some reason it was not installed, grab it here:

https://kubernetes.io/docs/tasks/tools/install-kubectl/

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 app.py:

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"))

That’s it!

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 simple-app-deployment.yml:

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:

https://cloud.google.com/kubernetes-engine/docs/concepts/deployment

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:

https://github.com/mustardgrain/simple-kubernetes-flask-app