Run an Application

Quick Note: The example is a Python-based Flask application that uses gunicorn. Don’t Panic you do not need to know Python, Flask, gunicorn or any other tool to understand to run the application.

The reason I chose to do a Flask app is that the standard nginx apps are not realistic and do not answer all the questions I had about starting up an application.

I am not going to do a deep dive into charts or Docker in this blog. Whilst this would be a good thing to do, I really want people to be able to spin up an application, make some minor changes and understand how it is hooked up.

First clone the repo, I have added the path I cloned it into but you may need to change it depending on how you tend to do coding and where you set up the volume for your k3d instance, we did k3d k3d create ... -v /home/user/Projects:/projects

App Code

The app folder is where the application code lives. This is the folder where a dev would be writing the majority of their code. In this case, it is very small and not very interesting.

The Chart

The chart folder is the helm chart, created using helm create chart command.

There are two files which I will reference. chart/values.yaml and devvalues.yaml The idea is you use the devvalues.yaml for local development and this will override anything you want to in the app, whereas values.yaml is used for non-dev environments.

chart/templates/flask-helm-example.yaml I have put all the application code in a single template file to make it easier to follow in the blog. This is not to say this is the best approach (though I quite like chunking the YAML per application chunk).

lines 1-46 set up a local volume which will link your local app code to the container, so any changes you make will be reflected in the container. This is wrapped in an {{ if... }} and .Values.local is set in devvalues.yaml

We then have the Service which exposes the pods created by the Deployment

The Deployment is largely uninteresting, with the following exceptions

line 79 is overridden in the devvalues.yaml file to be your local registry, this assumes you ran k3d create ... --enable-registry and set up your /etc/hosts as described before.

line 83-85 turns on reload for gunicorn, so when you update some code the app will automatically reload. A great alternative to this is pm2

line 99-102 and line 104-108 set up the volumes for your local code, this is defined in devvalues.yaml

line 118 is the path, which is not / in devvalues.yaml this is because the ingress uses the same hostname for all your applications, perhaps this is the case for your real applications but typically I have several hostnames for different applications and hence they can all run on /

There are also various parts around setting up a tls which is an example of how you might have tls setup for non-dev environments.

That is pretty much everything in this file worth noting. I have seen several examples using an environment variable but I feel that avoiding this makes the code cleaner, it also means you can use “dev” code for debugging just by turning it on when deploying.

Running and Developing the App

Here’s hoping that all makes sense to you, the key thing is, you have a devvalues.yaml file which overrides charts/values.yaml for local development.

You need to build and publish the container to your local registry

docker build . -t flask-helm-example:latest --network host

docker tag flask-helm-example:latest registry.local:5000/flask-helm-example

docker push registry.local:5000/flask-helm-example

It shouldn’t take too long to do the above if you change the Dockerfile you will need to re-run the above lines.

Once that is done run

helm install flask-helm-example -f devvalues.yaml ./chart

Notice that I have provided the -f devvalues.yaml without this, it will not mount the volume for local development and will not set up the ingress as you would have expected it to.

Then you can go to http://localhost:8080/flask-helm-example and see it working. You should change the app/main.py file to return a different string, and then gunicorn should reload. When you refresh the browser it will show you the new value.

Photo by Wil Stewart on Unsplash

Quick Summary

Amazing! You have an application which you can run locally and in a non-dev environment. Now go spread the word, developing Kubernetes applications is not only easy! Get set up in 9 lines of code:

# install kubectl

curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.17.0/bin/linux/amd64/kubectl

chmod +x ./kubectl

sudo mv ./kubectl /usr/local/bin/kubectl # install helm 3

curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

helm repo add stable https://kubernetes-charts.storage.googleapis.com # install k3d

wget -q -O - https://raw.githubusercontent.com/rancher/k3d/master/install.sh | bash # start k3d

k3d create --enable-registry --api-port 6550 --publish 8080:80 --workers 2 -v /home/user/Projects:/project # get kubectl to use your k8s instance

export KUBECONFIG="$(k3d get-kubeconfig --name='k3s-default')"

Then to install and run the application using local values

# build and push docker image

docker build . -t flask-helm-example:latest --network host

docker tag flask-helm-example:latest registry.local:5000/flask-helm-example

docker push registry.local:5000/flask-helm-example # start the helm chart with local values

helm install flask-helm-example -f devvalues.yaml ./chart

Useful Commands

Here is a cheat sheet of commands you may find useful, there are loads more, but looking through my history I seem to use these a lot

kubectl get events

kubectl get pods

kubectl logs <pod-name> --follow

kubectl cluster-info dump

kubectl exec -t <pod-name> -- /bin/bash helm install <name> -f <values>.yaml <chart-location>

helm uninstall <name>

helm status <name>

Questions

As I said at the beginning, feel free to ask questions. Note this blog was written Feb 2020 and may be outdated by the time you are reading this. I don’t want to claim I am an expert but I will try and find a solution to any problems you might have with you if I don’t have the answer, this will likely benefit me as well as you!

Happy coding!