The objective here is to create a Helm "chart" for our Kubernetes application. This will allow us to treat all of our Kubernetes resources as a single package and avoid using kubectl
to manually deploy individual resources step by step.
Helm also makes it easier to create different environments (dev/test/prod) which we will see the benefit of in later tutorials.
NOTE: This walk-through is significantly different to previous walk-throughs in the series, as we describe the process of getting to the result you see in the repo. This involves copying previous resources and modifying them to work progressively towards a working solution.
In all the previous walkthroughs, we deployed our Kubernetes app using the kubectl
command line application. This was painful because we had to remember to create the deployment and the service each time we wanted to release a new version of our app. If we created any more Kubernetes resources, then we'd have to remember to manually deploy those each time too.
On top of that, we also had to remember the exact file names of our Kubernetes manifest files. If we've built some automation around this, then we'd need to update our scripts each time we made any changes to filenames.
The problem is that we have to remember exactly how to deploy the application step by step. Our "application" (i.e, all of our Kubernetes resources packaged together) is something kubectl
has no idea about.
Helm is one of the solutions to this problem. According to the documentation:
A chart is organized as a collection of files inside of a directory.
In other words, Helm allows us to work from the mental model of managing our "application" on our cluster, instead of individual Kubernetes resources via kubectl
.
One of the other features of Helm is its ability to use templates in Kubernetes resources that are part of the chart. This means you can define values in one place and share them across multiple Kubernetes resource files. We'll also make use of this functonality as part of this walk-through.
In this walk-through, we'll turn our Kubernetes application into a helm "chart". This will let us deploy and update our entire application (all of the Kubernetes resources) using a single command line call to helm. We also won't even touch kubectl
during deployment.
Make sure you've got helm installed already. Follow the Installing Helm documentation to do this.
Once you have Helm installed, the next thing is to initialize the command line and get it running in your cluster.
➜ helm init
To know more about helm init
see the documentation.
Now that helm is ready we can start changing our ks4
baseline so that it uses helm.
-
Create the ks5 directory
➜ pwd ~/dev/github/redgate/ks/ ➜ mkdir ks5 # Delete node_modules first so the cp operation doesnt take too long ➜ rm -rf ./ks4/app/node_modules ➜ cp -r ./ks4/ ./ks5/ ➜ cd ks5
-
Create our new chart
➜ pwd ~/dev/github/redgate/ks/ks5/ ➜ helm create ks Creating ks
-
Inspect the chart directory
➜ pwd ~/dev/github/redgate/ks/ks5/ ➜ tree ks ks ├── Chart.yaml ├── charts ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── ingress.yaml │ └── service.yaml └── values.yaml 2 directories, 7 files
Note that helm has created some default Kubernetes resources for us. We want to use our existing resources, so we won't be using the yaml files that have been created for us.
-
Delete the default files
➜ pwd ~/dev/github/redgate/ks/ks5/ ➜ rm ks/templates/*.yaml # Delete NOTES.txt file # The contents of this are shown when you 'install' the chart. # But we won't use it in this walk-through ➜ rm ks/templates/NOTES.txt ➜ tree ks ks ├── Chart.yaml ├── charts ├── templates │ └── _helpers.tpl └── values.yaml 2 directories, 4 files
-
Copy our old development resources into the helm chart templates directory
➜ pwd ~/dev/github/redgate/ks/ks5/ ➜ cp ../ks4/config/dev.* ./ks/templates/ # Rename to remove the 'dev' prefix ➜ mv ./ks/templates/dev.ks.deployment.yaml ./ks/templates/ks.deployment.yaml ➜ mv ./ks/templates/dev.ks.service.yaml ./ks/templates/ks.service.yaml ➜ tree ks ks/ ├── Chart.yaml ├── charts ├── templates │ ├── _helpers.tpl │ ├── ks.deployment.yaml │ └── ks.service.yaml └── values.yaml 2 directories, 6 files
-
Tidy up unneeded resources
➜ pwd ~/dev/github/redgate/ks/ks5/ ➜ rm -rf ./config ➜ rm -rf ./scripts
At this point, we could deploy our helm chart. However, we'll first make use of Helm's template feature.
Helm creates some values in values.yaml
that were used in the default resources we just deleted.
We don't want to use any of these values, so we'll define our own. Replace the contents of values.yaml
with:
web:
name: ks5web
mountDir: /mounted-ks5-src
frontend:
name: ks5webfrontend
image:
repo: ks5webimage
tag: latest
containerPort: 3000
webserver:
name: ks5webserver
image:
repo: ks5webserverimage
tag: latest
containerPort: 5000
We'll now modify our Kubernetes resource files to refer to these values.
First, a quick explanation of the syntax:
.Release.Name
refers to the name of the helm release. This is a string you define when you first deploy your helm chart and stays the same through upgrades.
.Values.web.name
is a reference to the name
value under the web
data structure at the root of our values.yaml
file.
Whenever you want to refer to a variable in the values.yaml
file, you must start with .Values
. You can then pull values out of the data structures you have defined using the dot syntax.
At this point, you're ready to deploy the Kubernetes chart.
Start minikube
```bash
➜ minikube start
```
In one terminal, mount ks5 source code (leave this running):
➜ pwd
~/dev/github/redgate/ks/ks5/
➜ minikube mount .:/mounted-ks5-src
In another terminal:
➜ pwd
~/dev/github/redgate/ks/ks5/
➜ cd app
➜ yarn
➜ yarn build
➜ cd ..
➜ eval $(minikube docker-env)
➜ docker build -f ./server/Dockerfile -t ks5webserverimage .
➜ docker build -f ./web/Dockerfile -t ks5webimage .
Now we're ready to install the application with helm. The command helm install
injects the values from Values.yaml
into your Kubernetes resources and then deploys them all onto the cluster (in the same way kubectl
worked with the create
command for individual resources). Helm also keeps track of the "release" you make, which allows you to track release history, or rollback to a previous version among other things.
➜ helm install ./ks/ -n ks
NAME: ks
LAST DEPLOYED: Thu Jan 11 16:03:29 2018
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ks5web-service NodePort 10.0.0.173 <pending> 80:31316/TCP 0s
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
ks5web 1 1 1 0 0s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
ks5web-76588bdd75-r6226 0/2 ContainerCreating 0 0s
Your app is now up and running.
-
get pods
➜ kubectl get pods NAME READY STATUS RESTARTS AGE ks-ks5web-5dfd95cc95-9dnn5 2/2 Running 0 7m
-
service ks5 app
➜ minikube service ks-ks5web-service --url
Notice the name is now
ks-ks5web-service
previously we were usingks5web
. This is because we build the service name using helm. More specificallyname: {{ .Release.Name }}-{{ .Values.web.name }}-service
in theks.service.yaml
file. -
get web server logs
➜ kubectl logs ks-ks5web-5dfd95cc95-9dnn5 ks5webserver ➜ kubectl logs ks-ks5web-5dfd95cc95-9dnn5 ks5webfrontend
If you want to delete the application from your cluster, you can do this by using the helm delete
command:
➜ helm delete ks
release "ks" deleted
Note that this doesn't completely delete the release. You can still see it if you run helm list --all
➜ helm list --all
NAME REVISION UPDATED STATUS CHART NAMESPACE
ks 1 Mon Jan 15 12:56:08 2018 DELETED ks-0.1.0 default
You can rollback the delete by using the helm rollback
command with the listed revision number:
➜ helm rollback ks 1
Rollback was a success! Happy Helming!
This will bring the application back up in your cluster, which you can verify with kubectl get all
.
If you really want to permanently delete your release, you must use --purge
when running helm delete
:
➜ helm delete --purge ks
release "ks" deleted
You won't be able to bring this release back, so you'll need to run another helm install
.
One thing you'll notice is we've only moved our development environment into helm. A next step would be to leverage the values.yaml
file by offering a configurable "environment" variable. By testing the value of "environment" you can enable or disable parts of the Kubernetes resource configuration file, appropriate to the environment you're deploying to.
In future walk-throughs, we'll be exploring this idea.
We also haven't covered upgrading a release yet. This is possible with helm
and we'll come to this in another tutorial.