Create, Install, Upgrade, and Rollback a Helm Chart (Part 1)
In this post we will explain how we can use Helm for installing our application. In part 1 we will take a look at how we can create a Helm Chart for our application and how to package it. In part 2 we will cover how to install the Helm package to a Kubernetes cluster, how to upgrade our Helm Chart and how to rollback our Helm Chart.
Create a Helm Chart
A prerequisite for what we are going to do in this post is an installed Helm Client and Server (Tiller). We explained in a previous post how to do this.
We can create the required files for a Helm Chart manually, but the easiest way is to create it with the following Helm command where myhelmchartplanet is the name of your Helm Chart:
helm create myhelmchartplanet
This will generate a default directory structure with default files in it:
- charts: a directory to configure dependencies to other charts. We will not use this in our post.
- templates: a directory to configure Kubernetes, it contains templates which combined with the values.yaml will generate valid Kubernetes manifest files
- deployment.yaml: the configuration yaml file for the Kubernetes deployment
- ingress.yaml: the configuration yaml file for the Kubernetes ingress
- NOTES.txt: a text file containing notes which will be printed after installation
- service.yaml: the configuration yaml file for the Kubernetes service
- Chart.yaml: the chart yaml file containing e.g. version information
- README.md: a readme file with extra information about your chart, how to use it, which values can be adapted, and so on
- values.yaml: the values to be used in your chart. The values are used in the templates files
We will push this configuration to a GitHub repository (see tag v0.1.0). Next step is to adapt the default files to our needs. The application we will package and deploy is a simple Spring Boot application which prints a hello message when accessing the /hello URL. We used it before in a previous post and created a Docker image for it (we will use version 0.0.2-SNAPSHOT) which comes very handy at this moment.
Chart.yaml
So, first step is to adapt the Chart.yaml as follows:
apiVersion: v1
appVersion: "0.0.2-SNAPSHOT"
description: A Helm chart for Kubernetes
name: myhelmchartplanet
version: 0.1.0
Let's take a look at the different items:
-
apiVersion
: this is the Chart API version and should always have the value v1 (required) -
appVersion
: this is more informative and contains the version of the application which is contained in the package. In our case 0.0.2-SNAPSHOT. (optional) -
description
: a short description about the Chart (optional) -
name
: the name of the Chart (required) -
version
: the version of our Chart. As you can see, this is a different thing than the version of our application. They can be the same, but it is not required, as they are independent of each other. The version number has to be in the SemVer 2 format (required).
With this configuration, our Helm Chart will be named myhelmchartplanet-0.1.0.
values.yaml
With the values.yaml file, we can adapt several values which are used in the Kubernetes templates files. We will change the following default values:
-
image.repository
: the URL where our Docker image can be found -
image.tag
: the tag of the Docker image we want to deploy -
service.type
: we change it toNodePort
instead ofClusterIP
in order to expose it outside our cluster, just like we did before -
service.port
: we set it to 8080, the port our application is using -
service.nodePort
: since we use the type NodePort, we also have to set the port to use
The values.yaml file has the following content after our adaptations:
replicaCount: 1
image:
repository: mydeveloperplanet/mykubernetesplanet
tag: 0.0.2-SNAPSHOT
pullPolicy: IfNotPresent
nameOverride: ""
fullnameOverride: ""
service:
type: NodePort
port: 8080
nodePort: 30036
ingress:
enabled: false
annotations: {}
path: /
hosts:
- chart-example.local
tls: []
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}
service.yaml
Because we are using the service type NodePort
, we have to change something to the service.yaml:
-
targetPort
: the default value is http, we change it in order that the port of our application is being used -
nodePort
: we also have to define the property nodePort in order that our service sets it properly when being deployed to Kubernetes
Our adapted service.yaml is the following:
apiVersion: v1
kind: Service
metadata:
name: {{ include "myHelmChartPlanet.fullname" . }}
labels:
app: {{ include "myHelmChartPlanet.name" . }}
chart: {{ include "myHelmChartPlanet.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.port }}
protocol: TCP
name: http
nodePort: {{ .Values.service.nodePort }}
selector:
app: {{ include "myHelmChartPlanet.name" . }}
release: {{ .Release.Name }}
deployment.yaml
In the deployment file, we have to put the livenessProbe
and readinessProbe
in comments. These will check our application whether it is ready and alive, but we did not include the Spring Boot Actuator plugin in our application which will provide the URL to check the readiness and liveness of our application.
Check the Correctness of Your Chart
In order to check whether the changes you made to the different configuration files, you can issue the following command which will check the formatting and information:
helm lint myhelmchartplanet
I don't know exactly what is being checked, but it once gave no issues when the deployment to Kubernetes went wrong. It is therefore not a complete check on a correct Kubernetes configuration. Just be aware of that.
Package the Helm Chart
Now that we have adapted the chart configuration to our needs and that we have pushed everything to a git repository, it is time to package our Helm Chart. Execute the following command from outside your git repository, the command will search for a directory with the name of the Helm Chart from where it is issued:
helm package myhelmchartplanet
The package is being created (a tar gz file) and the following response is shown:
Successfully packaged chart and saved it to: /home/developer/myhelmchartplanet-0.1.0.tgz
As we said before, the name of our Helm Chart will be myhelmchartplanet-0.1.0 and here we can clearly see that.
Chart Repository
Before we can install the Helm package we created, we must make it downloadable. This is done by means of a Chart Repository. A Chart Repository contains packaged Helm Charts. It is not much more than a website containing an index.yaml and the Helm packages. When you browse to your home directory to the directory .helm/repository/local, then you notice that our packaged Helm Chart is added to this directory. The index.yaml file is automatically updated and contains metadata about the packages. It looks like the following:
apiVersion: v1
entries:
myhelmchartplanet:
- apiVersion: v1
appVersion: 0.0.2-SNAPSHOT
created: 2018-09-16T14:51:02.933628266+02:00
description: A Helm chart for Kubernetes
digest: sha256:a9c44411c15b7aa980f1c2d2f8deb29a82fcbb98eebdfc4ccecbf0910bf8e051
name: myhelmchartplanet
urls:
- http://127.0.0.1:8879/charts/myhelmchartplanet-0.1.0.tgz
version: 0.1.0
generated: 2018-08-26T18:01:30.000450767+02:00
In a production environment, you must ensure that your Helm packages are not stored on your local machine but are placed in a "real" repository. E.g. Google Cloud Storage, Artifactory, GitHub Page or just an ordinary webserver.
Summary
In part 1 of this post, we created our own Helm Chart, explained some of the files that are required, packaged our Helm Chart and made it available in a Chart repository. Next time we will continue with installing our Helm package to our Kubernetes cluster, upgrade it and execute a rollback.