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 terminal
hub 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~!