Ludovic Alarcon

Ludovic Alarcon .

Kubernetes and Cloud technologies enthusiast, DevOps believer - Golang and Dotnet Developer

Helm 101

What is Helm ?

From Helm repository

Helm is a tool for managing Charts. Charts are packages of pre-configured Kubernetes resources.

Helm allows to deploy and manage Kubernetes application as a unit of deployment which means you can manage your deployment like it is “one object”.
This unit of deployment is call a Chart and bundles one or more Kubernetes YAML manifests that define all the resources required by the application.
Helm also manage the upgrade and the rollbacks of your application.
You can think of it as a package manager for Kubernetes, like apt or homebrew.

To install helm

Helm chart

When you deploy an application on Kubernetes, you generally need to create different resources.
Let’s consider a simple todo API, the minimum you need is:

All those resources are defined in separate YAML manifests, and we need to manage them all to ensure our todo API run properly.
As we see previously, the Helm Chart bundles all the YAML files and treat then as a unit of deployment.
Instead of having to think about deploying all manifests we need, we can use simply one command.

> helm install ReleaseName MyChart

Helm really shine because it’s not just about deploy application but manage it.
When you install a Chart, it is versioned (everything is stored in Kubernetes secrets).
That allows us to quickly rollback to a previous version or upgrade our deployment.

It possible to list all helm charts installed on the cluster and see the chart version and the current revision as well.

> helm list -A

The -A option allows to see on all namespaces and the -n allows to specify a namespace (like kubectl binary).

Helm chart structure

Let’s create a Chart for our simple todo API.
To boostrap a new Chart, we simple need to run the helm create command.

> helm create todo

It will create a directory filled with everything needed.
The create command generate a sample chart that deploy nginx to get started easily.

todo
├── .helmignore
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

Let’s do some cleaning by deleting the charts folder, the content of the templates directory and the content of the values.yaml.

Helm Template

Let’s consider we have the following deployment manifest and two others for the service and ingress.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: todo-deployment
  labels:
    app: todo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: todo
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: todo
    spec:
      containers:
      - image: example/todo:1.0
        name: todo
        ports:
        - containerPort: 8080

As we previously see, to be able to install our application with helm we just need to copy our manifest in the templates directory and then use the helm install command.

But now, let’s imagine we want to deploy another version of our todo, we will have to duplicate our chart and change at least the name and the image’s tag.
The main problem with that is we have to maintain two charts which do the same things with only some different values.
This could lead to issue or oversight in the charts maintenance.

Helm tackles this by providing a templating system and replacing all mustache sections with provided values present in the values.yaml file.
The templating is really more powerfull than just replace the values when rendering, it also allows to add logic in charts, such as control flow, loop, etc..

This is how our above deployment could look like with templating.

# templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-deployment
  labels:
    app: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicas }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}
    spec:
      containers:
      - image: {{ .Values.image.name }}:{{ .Values.image.tag }}
        name: {{ .Release.Name }}
        ports:
        - containerPort: {{ .Values.containerPort }}

# values.yaml
# releaseName: todo
replicas: 3
containerPort: 8080
image:
  name: "example/todo"
  tag: 1.0

Let’s review the template:

You can provide values either with a value file using -f option.

> helm install ReleaseName MyChart -f values-override.yaml

or with the --set option

> helm install ReleaseName MyChart --set MyValue=2
# example with tag
> helm install todo todoChart --set image.tag=1.1

Advance Helm Template

Now, let’s see how could look like our ingress template.

# templates/ingress.yaml

{{- if .Values.ingress.enabled }} # Condition on enabled value
{{- $name := .Release.Name }} # variable declaration
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    {{- toYaml .Values.ingress.annotations | nindent 4 }} # Using helpers
  name: "{{ $name }}-ingress" # Using a variable
spec:
  ingressClassName: nginx
  rules:
    {{- range .Values.ingress.hosts }} # loop on hosts array in values
    - host: {{ .host | quote }} # current host, context change in loop to be set on the current object of iteration
      http:
        paths:
        {{- range .paths }} # loop on paths array in hosts section
          - backend:
              service:
                name: "{{ $name }}-svc"
                port:
                  number: {{ $.Values.service.port }} # $ allows to use root context
            path: {{ .path }} # Context is on current path object
            pathType: Prefix
        {{- end }}
    {{- end }}
{{- end }}

The ingress demonstrates a number of features of Helm templates:

The values.yaml file:

# values.yaml
# releaseName: todo
replicas: 3
containerPort: 8080
image:
  name: "example/todo"
  tag: 1.0

service:
  port: 80

ingress:
  enabled: true
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
  hosts:
    - host: "example.com"
      paths:
        - path: /
    - host: "example2.com"
      paths:
        - path: /

Package / Install / Upgrade / Uninstall

Package

When helm chart is ready we can package and install it.
Package a chart is basically bundle everything into a tgz named by combining its name and version.

# inside the chart folder
> helm package .
Successfully packaged chart and saved it to: /YOUR/PATH/todo-0.1.0.tgz

Install

A chart can be stored locally or hosted in remote chart repository.
So their is mainly 3 ways to install a chart

Upgrade

To upgrade the installed chart, we need to proceed like the installation but using the helm upgrade command instead.
The revision of the release will be incremented by 1.

> helm upgrade ReleaseName chart.tgz

When upgrading, we can either provide new values with -f option or reuse the one used previously with --reuse-values option.

> helm upgrade ReleaseName chart.tgz --reuse-values

To have information on a release, we can use the helm show command with one of its subcommands.

> helm show -h
This command consists of multiple subcommands to display information about a chart

Usage:
  helm show [command]

Aliases:
  show, inspect

Available Commands:
  all         show all information of the chart
  chart       show the chart's definition
  crds        show the chart's CRDs
  readme      show the chart's README
  values      show the chart's values

We can have information on the differents revisions with the helm history command.

> helm history ReleaseName

Finally, to rollback to a previous revision, we will use the helm rollback command.

> helm rollback ReleaseName Revision

Uninstall

To remove all resources associated with the installed chart, we need the helm uninstall command.

> helm uninstall ReleaseName

Debug Chart

To validate and/or debug a chart we can combined the --dry-run and --debug options on the helm install command.

> helm install ReleaseName chart.tgz --dry-run --debug

The chart will not be installed, but it will be rendered and validated.
In case of error, a stack trace will be provided to help identify and fix the issue.

It’s also possible to just render a chart or a file with the helm render command.

# inside the chart folder
> helm template .

# A specific file
> helm template . -s templates/someFile.yaml

To infinity and beyond …

To have deeper understanding, you can recreate the default chart and analyse all files. Also some readings:

Happy Helming!