skip to content
Tushar's Avatar Tushar Tripathi

What the heck is Helm?

/ 6 min read

Although I had seen Helm being used previously, it was always just a weird set of templating files. I recently dived deeper and built a good sense of what it is about. I hope the below helps someone who is familiar with containerization(e.g. Docker) and orchestration(e.g. Kubernetes) to understand what Helm is and how it can be useful.

A k8s package manager

You might have heard of Homebrew, Chocolatey or apt. These are package managers for MacOS, Windows and Debian respectively. They allow you to install and manage software on your computer. Helm in similar spirit, is a package manager for Kubernetes. It allows you to install and manage software in a Kubernetes cluster.

Helm Charts

The way package managers work is that they have a defined format for packages. For example, Homebrew packages are called Formula. These formulae are written in Ruby and have a specific structure. You can write your own formulae and install them using Homebrew or just use one from Homebrew Core which is a central repoistory of formulae maintained by the community.

The formula equivalent of Helm is called Chart. But don’t let the name confuse you, a chart is not a single file. It is a directory with a well defined file structure.

Application as a single unit

A chart is a collection of Kubernetes resources that are required to run the application. For example, if you have a web application, you might need a deployment, a service, an ingress, a configmap with the application also depending on a database. You can define all of these in a chart and then install it on a Kubernetes cluster.

What installing a chart does is that it creates the Kubernetes resources defined in the chart on the cluster. It’s like running kubectl apply on all the resources defined in the chart. But with versioning and templating. This lets you treat your application as a single unit and install it on any Kubernetes cluster with a single command.

You can also share the chart with the world, and anyone can install it on their cluster.

Release

A specific instance of a chart running in the Kubernetes Cluster is called a release. Each time a chart is installed, a new release is created. Once a chart is installed, and a release is created, it can be upgraded, rolled back or uninstalled.

For e.g. if you have a release todoList-v1 running on your cluster, and you have made some changes to the app, you can create a new release todoList-v2 and then upgrade the release todoList-v1 to todoList-v2. If something goes wrong, you can rollback to todoList-v1.

Helm is purely client side and there is no server component. It uses the Kubernetes API(REST+JSON) through the official Go client. Helm also uses Kubernetes’ Secrets to store the release information.

Helm Chart Structure

Let’s look at the barebones structure of a chart for a simple application todoList.

todoList
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── service.yaml
└── values.yaml

Chart.yaml

This file contains metadata about the chart. A minimal Chart.yaml file for our todoList application would look like this:

apiVersion: v2
name: todoList
version: 0.1.0 # SemVer incremented when you make changes to the chart
appVersion: "1.0.0" # version of the todoList app
dependencies: []

The dependencies field allows us to specify other charts that this chart depends on. This is useful when we want to install multiple charts together. For example, installing a database with our todolist App. A full list of fields can be found here.

templates directory and values.yaml

The template in simple words is a file with placeholders that are replaced with values from values.yaml when the chart is installed. For our todoList application, we need a deployment and a service. So we create two files deployment.yaml and service.yaml in the templates directory with placeholders for the values that we need to replace.

Here is a sample deployment.yaml file for our todoList application:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-deployment
  labels:
    app: {{ .Release.Name }}
spec:
    replicas: {{ .Values.replicaCount }}
    selector:
        matchLabels:
        app: {{ .Release.Name }}
    template:
        metadata:
        labels:
            app: {{ .Release.Name }}
        spec:
        containers:
            - name: {{ .Release.Name }}-container
            image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
            ports:
                - containerPort: {{ .Values.image.port }}

And the corresponding values.yaml file:

replicaCount: 4
image:
  repository: "todoList"
  tag: "v1"
  port: 8080

When we install the chart, the placeholders in deployment.yaml are replaced with values from values.yaml and the resulting file is used to create the deployment. For example, the {{ .Values.replicaCount }} placeholder is replaced with the value of replicaCount from values.yaml.

There are also some other built-in variables such as .Release.Name used above. Release name is the name of the release that is created when the chart is installed.

Is templating just find and replace?

Not really. The Helm template language is built on top of Go templates and is quite powerful. You can use conditionals, loops, functions, arrays, string utilities, regex, math and much more. Combined with unix like pipelines and multiple built-in functions, you can do a lot of things with Helm templates. A few examples:

# conditional based on the value of .Values.image.tag
{{- if eq .Values.image.tag "latest" }}
imagePullPolicy: Always
{{- else }}
imagePullPolicy: IfNotPresent
{{- end }}

# array
ports:
{{- range .Values.ports }}
- containerPort: {{ . }}
{{- end }}

# dict
{{- range $key, $value := .Values.ports }}
- name: {{ $key }}
  containerPort: {{ $value }}
{{- end }}

# string functions piped together
{{ .Values.image.label | quote | upper | trunc 16 | repeat 3 }}

ArtificatHub: Helm’s central repository

Helm has a central repository called ArtifactHub with thousands of charts. For example, Prometheus can be installed on a Kubernetes cluster using Helm with a single command:

helm install prometheus prometheus-community/prometheus

Charts can also just be stored privately. For our todoList application, we can store the chart alongside the application code in the same git repo for e.g. and write a simple CI/CD pipeline to deploy it to our cluster. Or in other words, install the chart to create a release and upgrade the release for every commit to the master branch.

Next Steps

Check out the “Using Helm” page on the official Helm docs to see common commands and workflows. You can also check out the Central Hub for examples of popular charts.