Join our Discord Server
Ajeet Raina Ajeet Singh Raina is a former Docker Captain, Community Leader and Distinguished Arm Ambassador. He is a founder of Collabnix blogging site and has authored more than 700+ blogs on Docker, Kubernetes and Cloud-Native Technology. He runs a community Slack of 9800+ members and discord server close to 2600+ members. You can follow him on Twitter(@ajeetsraina).

What is Helm?

11 min read

Thanks to Collabnix community member Mewantha Bandar  , a Senior Software Engineer at IFS for contributing this content for KubeLabs – The #1 Kubernetes Resources for all Levels. Do you have anything exciting to share with Collabnix community? Do visit Collabnix community Slack and we might feature you in Collabnix website.

If you have used a Linux environment (and it’s safe to assume you have), then you are already acquainted with package managers (apt, yum). Helm basically the same thing, but for Kubernetes. Imagine you want to add MongoDB to your existing Kubernetes implementation, and this resource comes with services, deployments, secrets, stateful sets, etc… Taking the Yaml files of each of these resources and deploying them one by one into your Kubernetes cluster would be both cumbersome and time-consuming. Additionally, this task would also be repetitive since various developers around the world may gather these exact same Yaml files to set up MongoDB over and over again. This is where Helm Charts come in.

What are Helm charts?

A Helm chart is, simply put, a collection of Yaml files. Imagine someone takes all the necessary Yaml files to set up MongoDB and then bundles them into a package. Similar to how normal package managers work, it would then be a simple matter to upload this package into a common repository. Once that’s done, any other developer looking to set up MongoDB would only have to download this package instead of doing the legwork themselves by simply writing:

helm install <chart>

What is a Helm repository?

This is a place where Helm charts are storedm and where you can download them. Artifact Hub is a centralised repository for Helm packages and is extensively used by Kubernetes developers in their daily work.

What is a Helm release?

This is once single instance of a chart. Even within a single Kubernetes cluster, the same chart can be installed multiple times. In order to facilitiate this, each installation is considered to be a release. So if you want 2 instances of MongoDb running in your cluster, it is just a matter of installing the chart twice.

Helm as a templating engine

If you have used Kubernetes for even a simple project, you would have noticed that the Yaml files you create for various resources tend to get repetitive. For instance, deployment files may be identical to each other apart from the image they use. This means you would end up creating a deployment file for each image even though they have only minor differences. Helm can step into the rescue here as well, by introducing templating to Yaml’s. Now, you could get rid of all the duplicates and replace them with a single Yaml file. But what about the parts that are different? Well, Helm allows you to dynamically set those values. So instead of hardcoding the image name like this:

    - name: nginx
      image: nginx

You could convert it into a template:

    - name: 

Then set the name and image dynamically.

Now that we have a broad understanding of how Helm works, let’s first install a helm chart and see what this is all about, before taking a deep-dive into the specifics, starting with a deeper introduction to Helm charts.

Installing a chart

The easiest way to get into the subject is to do it hands-on. So let’s go ahead and install a Helm chart.

Firstly, you must have an active Kubernetes cluster. The easiest way to get this up and running is using Minikube.

If you have a Kubernetes cluster up and running, then it’s time to install Helm. The installation is fairly straightforward, and the full installation steps can be found hereMake sure you install Helm 3. There are some significant changes between Helm 2 and Helm 3, which means that the below tutorial will not work if you use Helm 2 instead.

Once this is done, you can add a chart repository. Note that this isn’t the actual chart. Rather, it is the repository where various packages are stored. The Artifact Hub has a comprehensive list of chart repositories. We will install the bitnami chart repository:

helm repo add bitnami

Once this command has run, you can explore this repo which will show you all the available charts within this repository.

helm search repo bitnami

Next, let’s install an example chart. Before we do that, we have to ensure we get the latest list of charts. Do that using:

helm repo update 

The chart we will install is the MySql chart. Install that using:

helm install bitnami/mysql --generate-name

Note that --generate-name will generate a name for the release. You can also set your own name like so:

helm install my-custom-name bitnami/mysql

The chart you just installed is considered a release. This means that each time you install a chart. a new release is created. Thanks to this, you can go ahead and install a chart multiple times into the same cluster.

Let us now explore the MySQL chart we just installed. Run:

helm show chart bitnami/mysql

This will output the details (metadata) about the chart. For example, you get details on the repository, version, and keywords this chart will match for when you search on Artifact Hub. Basically, anything that makes this specific chart stand out. You can get now get a list of available helm charts by running helm list. You should be able to see the unique name of this helm chart from here (something like mysql-xxxxx). This name can be used to get the status of the helm chart:

helm status mysql-1652869723

Uninstalling the chart is as easy as calling helm uninstall with the chart name. You could also use the flag --keep-history if you want to get rid of the chart but keep the release history.

Now that we have the basics out of the way, let’s do a deep dive into Helm charts.

Helm Charts Deep dive

You already know what a Helm chart is. Now, we are going to see the structure of a Helm chart.

First, a folder must be created to house all the files pertaining to the Helm chart. This folder should be named the same as the chart itself. Drawing inspiration from the official Helm docs, let’s imagine we are creating a Helm chart for WordPress. The general file structure would look like this:

 ┣ 📂charts
 ┣ 📂templates
 ┣ 📜Chart.yaml
 ┗ 📜values.yaml

First, let’s consider the Chart.yaml. This is where chart information is defined. The Chart.yaml provided here is taken from the Helm docs and describes the file in great detail.

Next, let us consider the templates folder. Inside this folder, you may define as many Helm templates as you wish. In this case, I have added a template called configmap.yaml. As you can see, the template uses a placeholder notation {{}} in order specify that these values can be dynamically changed later on, and this is where the values.yaml comes in.

The values.yaml is, simply put, the place where the values passed into the Helm template are stored. The values stored within this file can then be accessed by templates using .Values.<value>. You might recognize the Yaml format since it closely resembles a Yaml used to define an ordinary Kubernetes resource.

Finally, we have the the charts folder which holds the chart dependencies. If this chart defined within Chart.yaml depends on any other charts, that information would be stored here.

Customizing charts

If you were going to create a brand new chart, you would obviously have to customize it to suit your needs after running helm create. However, even if you are using a preexisting chart, you would still want to edit the chart to your specific use-case. Most of the time, pre-made charts are easily configuable. Going back to our WordPress example, you can see what values are configurable by running:

helm show values bitnami/wordpress

The output will show that you can configure things such as the image registry, image pull secret, etc… You can then override these values using a Yaml file. A comprehensive list of methods and limitations of overriding is provided in the official Helm docs.

Hands-on lab

Firstly, you must have an active Kubernetes cluster. The easiest way to get this up and running is using Minikube.

If you have a Kubernetes cluster up and running, then it’s time to install Helm. The installation is fairly straightforward, and the full installation steps can be found here. Run the Helm create command to get started:

helm create hands-on-helm

You will notice that the above directory structure has now been created and that these are not empty files, but have detailed descriptions and templates within them. Open up the values.yaml present and you will notice that this is a basic resource to start a simple Nginx server. The Chart.yaml contains some basic metadata information about the chart. Meanwhile, you can see that the charts folder is empty. This is because this chart has no dependencies as of yet.

The templates folder holds sample templates. Currently, there are templates for:

  • Deployments
  • Services
  • Ingresses

These templates can act as a reference for you to start with so that you don’t have to begin from scratch.

Template functions

Speaking about templates, now is a good time to mention that Helm uses an extended version of Go templates. One of the biggest additions to the Go templates is the include command. This simply allows you to include a template within a template whose output can be piped to an operator. Like so:

{{ include "included_template" $value | indent 2 }}

The next notable addition is the required keyword. Declaring an entry as required would mean that an empty entry would result in an error, resulting in the template refusing to render.

{{ required "A valid foo is required!" }}

The tpl function comes next. This function allows strings to be evaluated as a template within a template. The syntax for this is:

{{ tpl .Values.template . }}

Image pull secrets

Image pull secrets are not only used by Helm but also by Kubernetes in general. However, Helm allows the secret to be written into template files, similar to how the values.yaml works. For example, imagine the credentials are stored in a yaml like this:

  username: someone
  password: sillyness

A helper template can then be defined to use this YAML:

{{- define "imagePullSecret" }}
{{- with .Values.imageCredentials }}
{{- printf "{\"auths\":{\"%s\":{\"username\":\"%s\",\"password\":\"%s\",\"email\":\"%s\",\"auth\":\"%s\"}}}" .registry .username .password .email (printf "%s:%s" .username .password | b64enc) | b64enc }}
{{- end }}
{{- end }}

This template can then be used within all helm charts:

.dockerconfigjson: {{ template "imagePullSecret" . }}

This covers the basics of Helm charts, should you need to create one. However, only narrowly covers the full breadth of what Helm has to offer. For more tips and tricks, visit Helm official docs. Now, let’s move on to Chart hooks.

Chart hooks

Chart hooks allow you to have flexibility over what happen during the various stages of a release lifecycle.

What is a release lifecycle?

A Helm release refers to a single instance of a chart that is applied on a cluster. So it follows that a release lifecycle is the lifecycle of this instance. This includes the installation, upgrade, deletion, etc… of charts, and chart hooks allow you to do various things in these stages.

What kind of things?

A ‘hook’ would have a resource delcared in it. For instance, if the resource is a pod, then this pod will spin up at the specified time. If it is a job, then the job will run.

What are hook weights?

If you want to run 2 (or more) hooks, then there should be a way for you to specify which hook should run when. You could have a hook that builds on work done by a previous hook, and it wouldn’t work well if hooks started executing randomly. This is what hook weights are for. By specifying a number (as a string in the actual yaml). If you were to set a hook with weight -5, that would run before a hook with a weight of -4.

Chart hook examples

A full list of possible chart hooks can be found in the Helm official documentation. In this case, we can consider the process of what happens when a Helm chart is installed. Helm has two possible hooks for use in this case, pre-install and post-install. Pre-install executes after any templates are rendered and before any resources are loaded into Kubernetes. Post-install runs after everything is in place.

If you were to use a pre-install hook, the normal install process would go on until the templates are rendered. At that point, Helm starts loading your hooks and waits until they are ready before loading resourecs into Kubernetes. Going back to our example where the hook has a pod declared in it, the pod will spin up at this point, run to completion, and then finish.

If a post-install hook was also in place, this would come into effect after resoureces have finished loading. The post-install hooks would run and Helm would wait until these hooks are ready before continuing. Something you should note is that Helm expect the process declared in the hook to finish, and will halt everything until that point is reached. If there is an error here, the operation will fail.

Creating a hook

Ok, you now know what a hook is and what it does. So how do you write one? The most important thing to note here is that a chart hook is a template file. If you know how to create Helm templates, then you’re well on your way to creating chart hooks. Since each hook run a Kubernetes resource to completion (such as a job or a pod), you will essentially be defining a Kubernetes resource as a hook. So you can go ahead and take some simple yaml that spins up a pod, then add a couple of lines to make it a hook.

These lines should be added under the annotations section of the yaml and should include the point at which the hook should jump in, the weight of a hook, and the delete policy for that hook. As you may notice from the example below, a single resource can have multiple hooks. This applies to hook deletion policies.

    # This is what defines this resource as a hook. Without this line, the
    # job is considered part of the release.
    "": post-install,post-upgrade
    "": "-5"
    "": hook-succeeded

Next, let’s move to chart testing.

Testing charts

You would rarely (if at all) make a chart to create a single resource. After all, the whole point of a chart is to have multiple resources grouped together in a reusable package. Since these bundled resources would generally work together, it is important to make sure that this collaborativeness is put to the test.

This test goes inside the templates folder of your chart, and needs to have the test annotation present for it to be considered a test:

    # This is what defines this resource as a test test

You might notice that this test is similar to a hook. This is because the test is a hook. It hooks in at a given point and runs the test. If you followed the hands-on lab from the previous lectures, you should be able to see a sample test that was created by the helm create command. It is located in hands-on-helm\templates\tests and should give you a basic idea of what the test looks like. Of course, this test doesn’t do much; merely runs a busybox instance and does some basic validation. However, you can set up some pretty complex tests using this.

Once you have finished writing your test, it’s time to test it. Simply install your chart and once the release is created and pods have spun up, the tests should begin.

Now, let’s move on to Chart Repositories.

Chart repositories

You already know what a chart repository is and how to install a chart off an existing repo. So let us consider how we would go about creating a chart repo and serving it, as well as a deep-dive into chart repositories.

While chart repositories such as ArtifactHub exist, you may want to create your own chart repositories. A chart repository is simply an HTTP server whcih has an index.yaml in it. The HTTP server does not need to be a physical server, and can instead be a GCS bucket, S3 bucket, or even something like GitHub pages. Going back to the index.yaml, this is neccessary to hold a reference to all charts in a repo, and is generally hosted on the same server.

To create this file, use

helm repo index

This generates an index file. If you have packages charts (such as alpine) present in the local directory where you run this command, those charts will be taken into consideration.

Hosting a chart

Now that your chart repo structure is complete, let’s go ahead and host the chart. There are a ton of ways to achieve this, and we will be using GitHub pages. This official guide should be able to start you off with creating a GitHub page.

Once your page is setup, there are some other steps that need completing in order for you to convert it to a Helm chart repo. You need to use chart releaser. Chart releaser is a GitHub action workflow, which is essentially a pipeline you can use to automate releases. Read more about GitHub action here.

You would likely have created a GitHub repository at this point. Introduce a folder called charts at the top level, then place all your charts there. It is also advisable to have a readme at the root level which acts as a guide to anyone using your repo. Once this is done, you can start setting up your GitHub workflow.

How does the workflow work?

The chart releaser action will convert your GitHub repo to a Helm chart repo. Every time you push to master, every chart present in your project (inside the charts folder) is checked. If there is a new version, a GitHub release is created with the name of the chart version, and an artifact is created. The index.yaml is created (or updated) with the relevant metadata, and this is finally hosted on your GitHub page. Note that you can use Helm testing actions to ensure nothing breaks during this automated process.



Have Queries? Join

Ajeet Raina Ajeet Singh Raina is a former Docker Captain, Community Leader and Distinguished Arm Ambassador. He is a founder of Collabnix blogging site and has authored more than 700+ blogs on Docker, Kubernetes and Cloud-Native Technology. He runs a community Slack of 9800+ members and discord server close to 2600+ members. You can follow him on Twitter(@ajeetsraina).
Join our Discord Server