All about Helm
Assume we have planned to create cluster full of deployment , services, persistent volume claims etc
If we manually do that, it will take time and we have to keep a lot of things in our mind
We also need to create multiple yaml file etc. Later when you want to delete something, you have to keep in mind about the dependencies. While doing that we need to search for things that will take hours.
To solve this, we have helm
We just use a single command to install all of that
If we want to customize , we just need to change values in the yaml file
In case we need to upgrade , we need one command to upgrade each and every object
In case of any mistake, we can easily rollback to the earlier version
Uninstalling the things are as easy as other tasks
How to install?
Use sudo snap command or curl it
Helm 2 vs Helm 3
Helm 1 was launched in 2016, Helm 2 on 2016 well whereas Helm 3 on 2019
Helm 2 used to lack Role Based Access Control (RBAC), Custom Resource Definitions.
To solve this issue, we had to install Tiller in between
By default Tiller was running in Admin mode
Once in Helm 3, RBAC and Custom Resource Definitions were introduced, Tiler was removed
And now, with RBAC we can set limits and restrictions for users
Apart from Tiller, Helm 3 had the 3 Way Strategic Merge Patch option.
What is that?
Assume that , using Helm2; you have installed wordpress
That creates a revision 1. After that, you upgrade the wordpress and it creates another revision
Again, you decided to rollback to the old version and that creates another revision
What if rather than using helm for upgrade, you decide to upgrade it manually?
Now when you want to rollback using helm, helm 2 can’t actually rollback to revision 1
But for Helm 3, it’s different. It can detect Live state, Previous Chart and current chart. In this way, it creates a 3 way merge patch.
It can rollback or update using this method.
Helm Charts
Using charts we do install things
Once something is installed, a release is created. The release itself has multiple revisions (install, update, rollback etc)
Also, helm saves metadata about our system, installed software etc. It can easily track changes though this
It saves this on our kubernetes cluster
But how this Helm chart look? What is that? To understand this, let’s assume to create a nginx server and a service to expose it.
Here we have deployment.yaml file to create the nginx server and service.yaml file to create a service.
But here you can see certain things are not as usual. WE have used .values.images
or .values.replication
. This format is called templating. And while using publicly available helm charts, this is the only thing we have to change via values.yaml
For real world usage, it’s much more complicating
Also, keep in mind that while installing something we need to specify the release name.
We have to specify that so that, we can distinguish between releases
You may again ask where to find all of the helm charts! All of the available ones are stored in ArtifactHUB
Now remember, we talked about templating where we have values.yaml . But alongside that, we have chart.yaml file
Now, let’s look into the chart.yaml file
Helm 2 didn’t have dependencies and type and therefore, helm3 has this apiversion option to differentiate between application being created using helm2 or helm3
appversion shows the version of the appliction, version shows the version of the chart, the name shows the name of the chart, type shows if that’s an application or a library, dependencies has the dependent applications. Here wordpress application require a wordpress server and a database server. Here we have included mariadb database included using it’s own chart.
There is a keyword list attached to find the wordpress chart in a public chart repository.
Also, we can add maintainers name and mail, home , icon for the wordpress chart here.
How does a chart directory look?
A chart directory generally have templates (deployment.yaml, service.yaml files using .values.images etc), values.yaml file, chart.yaml file, LICENSE, README.md, other dependencies on the charts folder
Let’s install wordpress
Let's install a wordpress application using [artifact](https://artifacthub.io/packages/helm/bitnami/wordpresshttps://artifacthub.io/packages/helm/bitnami/wordpress)
or search it using terminalhub search hub wordpress
Let's follow the one from artifact
helm repo add bitnami
https://charts.bitnami.com/bitnami
Make sure to start the kubernetes (minikube start)
helm
install my-wordpress bitnami/wordpress --version 24.1.5
check out the list of release (once something is installed using chart, it’s created as a release). We have also created a release called my-wordpress
Uninstall it using uninstall command
We also can see all the repository (charts) we have added locally by this
helm repo list
If we want to update them, use
helm repo update
Customize wordpress
When we installed wordpress using helm, we had default values set in the values.yaml file
Our goal is to change the wordpressblog name. We can do that here using —set
If there are much more things that we want to customize, we can just set that in our own yaml file (custom-values.yaml) and them pass this on the command line using —values <yaml_file_name>
Or, we can make changes to the values.yaml file rather than setting a variable value or pass a file. For that , we need to pull and unzip that.
Then we can open the folder in VScode and make changes to the values.yaml file.
Once done, we can install the wordpress and launch the release.
Lifecycle management
Assume that we have installed an old version of nginx server (chart version 7.1.0)
Then months passed by and we came to know various vulnerabilities , secrets to update and many more.
Firstly we checked the pod details
Here nginx version is 1.19.2. But we want to update that. For this , we used the upgrade command and helm created another revision with this changes
We can now see the latest pod with updated nginx server (1.21.4)
We can also see changes on each revision
In case we roll back to revision 1, it actually creates a new revision . But yes, it has the same features of revision 1.
But it’s important to understand that while the versions do rollback, the data external or internal remains same. For example, a mysql database might be rolled back but the data remain same etc. Assuming revision 1 of mysql database had 100mb of data, revision 2 had 39 mb of data (which is not there in revision 1). Now, once we role back, to revision (technically a new revision is created), we still have 29 mb of data.
These are solved using chart hooks.
Creating a helm chart
Assuming we want to create a helmchart, we just need to use create command
This will create an architecture for us. Using this, we can make changes to the file and create our helm chart
If we look into the Chart.yaml file created, we can see some default values already set there
We can also see some yaml files in the templates folder.
We can remove them and add our yaml files which we want to use the chart with.
We are good to go to create our chart now.
Let’s create a release (hello-world-1) now using this chart.
We can check the deployment name too. But what if we want to create another release using the chart?
It fails because a deployment named hello-world already exists. Why? Because in our deployment.yaml file we fixed the deployment name. We shouldn’t have done that.
Rather than that, we could use this in our deployment file. IN this way, the deployment name would be created using the release name
Or, we can use other things in that part to make it different
But if we use values.<something>
there, it will take the value from values.yaml file
So, now we can create different releases of our chart
to sum up, this is how it works
Verifying if the chart is working or not
We use lint to check if we had any typo while creating the chart
We can use template command to see how our chart will look
Here you can see that the replica value is 2 which it got from deployment.yaml and values.yaml
If we pass a release name with it, it also shows the release name in the deployment (Note: Nothing is created yet. It’s just showing the demo how it will look if we launch)
Apart from this, we can now dry tun the things (dry run runs the application but is not permanent. It’s used for testing)
While so, we can see our mistakes which can’t be detected using lint and template
We can then correct them and run the application using the chart
Functions
What if we forget to add values in the values.yaml file? In this way, the deployment will fail
to prevent this, we can create functions which will take default value if the user forgets to add values in the values.yaml file
These are some of the functionalities we have (uppercase the image name nginx to NGINX, quote the image nginx to “nginx”, replace x of nginx to y, shuffle the nginx etc.)
So, in our case if we want to solve the issue setting a default value, we can do this like this
Here you can see deployment file in templates have default “nginx” set and values.yaml have nothing.
Once we run the chart to create deployment, it will automatically use nginx as nothing is given in the values.yaml file
Pipeline
Remember, we use echo to print a string
But to translate the same string we pass a pipe (|) and then use tr (translate) smaller a-z (a-z) to upper case (A-Z)
Now it prints the abcd as ABCD
Earlier we saw how upper function is used to get uppercase words
Here image value is nginx which we use upper to make NGINX
We can also do the same thing using pipe
We can add more functions like adding quotes using the pipe
basically this is how it works .values.image.repository gets the value nginx for example and it’s passed to upper though pipe and we get NGINX. Then it’s passed to quote though the pipe and we get “NGINX”.
We can also pass this to shuffle and get something like this
Conditions
Assume that we want to add tags in our different releases.
To do that, we can set the value in values.yaml file
But we also don’t make it a must to add a tag for releases. What to do then?
We can add {{ if.Values.orgLabel }}
to see if any orgLabl
value is given in values.yaml or not, if given take the value from .Values.orgLabel
, if not, avoid using {{end}}
Also we can add conditions too see if the orgLabel is set as “hr”. If yes, we set the org value as “human resources” etc.
Scope
When we set some value in yaml, this is how the tree looks like
We can also short the scope by setting the scope . Here we specified that all files mentioned here are within values.app
Now, we can remove .Values.app and set just ui.bg, ui.fg etc to get access to files
The same can be done, to get into ui scope and db scope
Later if we want to see the Release value which is not in our scope, we will find error
To solve this, we use $ to mean the root scope. In this way, we can access any value again
Ranges
Assume that we want to add a list of regions specified in the values.yaml file to our final configmap.yaml launched after we used the chart.
Here is the values.yaml file
This is our final goal
To solve this,we need to keep in mind that every value we have in values.yaml file is actually like this
We want to print something like this in the configmap.yaml file.
So, let’s add a range.Values.regions
which will get one region value every time it loops
We then add - {{ . }}
to mean a value from the regions
Now the output of the configmap.yaml will look like this
We also need quotes, so pass this though a pipe and quote function {{ . | quote }}
Now, we have our desired value.
Named Templates
Sometimes we need to add tags , labels etc which are fixed
These are some repeating lines which we need to add manually every time. To solve this, we can use _helper.tpl ( a template file) with the service.yaml file
We also need to mention {{ - template “labels”. }
here template labels will get the labels value from _helper.tpl and .
ensures that we get the Release name etc from root.
Note: Check this image for reference
now as we wanted to repeat the same labels in our file, we can use it like thi
But it won’t work because we have to keep in mind that, everytime we use the labels from _helper.tpl, we need to add more indentation.
The current output might look like this (right most one)
so, we can add more indentation like this for the second and third one
Here we passed the value and used pipe and indent function to add 2 space and 4 space.
But it won’t work as well because templates can’t be passed to a function. To solve this, we use include function here
Now, you can see the right most file has our desired indentation.
Chart Hooks
Once a person wants to upgrade an application, helm verifies it, renders it and upgrade it.
Earlier we talked about the data issue which can be resolved and kept backup using chart hook. We can do that here prior to upgrade one.
It’s a pre upgrade hook where we can do that task.
We can also add more hooks like mailing us after a successful upgrade
So, in this way, we can have so many hooks of our choice
But how to configure the hooks?
Assume we want to backup our data using the backup.sh (script) and we want to run it in the pre-upgrade phase. To run that once, we can use it as a job (like cron jobs)
Then we create a backup yaml file (here backup-job.yaml) and add annotations to work it in the pre-upgrade phase
Perfect, now as our chart is used to upgrade, this back-job.yaml file will use backup.sh to backup the data.
What if we have planned more pre-upgrades like setup banner, email announcements?
To solve this, we can add weights to the task and helm will apply them according to the order
For example, we can set the weight 5 to our backup job like this
What to do after the task is task is done?
We need to delete resources and show a message. We can do this like this
Packaging and signing charts
Assuming we have created all the files needed to create our chart. Now we need to package it and upload
This is how we can package our chart to an archive format (tgz)
Now, prior to upload, we need to generate a public and private key to make them upload process safe
Let’s generate one using the name “John smith” for now
The public key should be uploaded so that users can use that and verify the authors.
Helm currently prefers older format and thus we store the keys in secring.gpg
Then we package the keys with our file. Here we must add —sign , —key with the Name we provided.
Then our keyring with the keyring we created.Finally the chart name
Now we can see a prov file (provenance file)
to verify we do this
users do this like this
Also, we as a user can verify packages from online like this
Upload the package
Now we have our package, provenance (we created .prov file) and we create an index.yaml file which has all the information about chart repository
we have our normal chart folder (nginx-chart), packaged folder (,tgz), provenance folder (.prov)
We can create a new folder and move our packaged folder and provenance folder in it
Note: The last command would have nginx-chart-files instead of gnix-chart-files
Then we use this to complete
Now we have our index.yaml file
We can now upload this to any of our chosen server
Assuming we uploaded that to the google cloud. Now anyone can use the link (example-charts.storage.googleapis.com) to add this and install the application
Done~!