How to develop a Helm Chart

This tutorial assumes that you have basic knowledge of Kubernetes and a working Kubernetes cluster.

What is Helm?

Helm is a package manager for Kubernetes that allows developers and operators to more easily package, configure, and deploy applications and services onto Kubernetes clusters.

Helm is now an official Kubernetes project and is part of the Cloud Native Computing Foundation (CNCF), which maintains the highest standards of quality for software in the cloud-native ecosystem.

What is a Helm Chart?

A Helm Chart is a tool for simplifying the deployment and management of applications on Kubernetes. For those familiar with Kubernetes, you’ll know that even a basic application can require numerous YAML files to define its components: Deployments, Services, Ingresses, and more. Managing these individual files as your application grows can become complex. Helm Charts offer a solution to this issue, packaging all these resources into one neatly organised unit that represents your application.

Installing Helm

Helm can be installed on Linux, macOS and Windows. More options can be found on the official Installing Helm page.

Linux:

$ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

macOS:

$ brew install helm

Windows (using Chocolatey):

$ choco install kubernetes-helm

A more comprehensive list of options can be found on the official Installing Helm page.

You can then check if everything got installed correctly:

$ helm version --short

Creating a Helm Chart

The Helm Chart is essentially a collection of files inside a directory. The directory name is usually the name of the chart. It contains template YAML files for all the Kubernetes resources required for deploying an application, a Chart.yaml file that contains description of our chart, and a values.yaml file that lists the default values for our template files.

Let’s create our first starter chart:

$ helm create hello-world

This command creates a chart with the name you specify, along with default files and folders. You can inspect the directory structure:

$ tree hello-world
hello-world
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

The templates directory is for template files that are sent to the rendering engine and then to Kubernetes. They are the same Kubernetes YAML files, just that they are templatized.

The values.yaml file is very important and connected to the templates, since it contains the default values for the template files.

The charts directory may contain (not required) other required charts (dependencies).

You can find more information in the official Getting Started page.

Editing the Chart.yaml file

Modify the Chart.yaml file to reflect the metadata of your chart. Be sure to change the name, description, and version of your chart.

apiVersion: v2
name: hello-world
description: A Helm chart for Hello World
type: application
version: 0.1.0
appVersion: "1.0.0"

As you can see, we are defining apiVersion (v2 for Helm 3), name, description, type (application in our case), version (version of this chart) and appVersion (version of the actual app e.g. nginx in this case). The entire list of supported fields can be found on the official Chart.yaml page.

We should increment the version when we make changes to the chart and appVersion each time we make changes to the application.

Editing templates

In many Helm tutorials, you’ll find the suggestion to delete the templates directory and start from scratch. However, this requires manually creating every resource definition file. For our tutorial, we’re taking a different approach.

Instead of deleting, we’ll use the pre-generated files by helm create as a starting point. These files provide a good default structure for our chart, covering common Kubernetes resources like Deployments, Services, and Ingresses. This way, we can focus on customising the Helm chart to suit our needs, leveraging Helm’s ability to streamline Kubernetes application deployment.

Editing values.yaml

The values.yaml file is an essential part of a Helm chart, providing default configuration values that can be utilised throughout the rest of your Helm chart. Let’s delve into how we can adjust important parameters:

image:
  repository: nginx
  tag: stable
  pullPolicy: IfNotPresent
  pullSecrets: []
  • repository: This is the name of the Docker image that will be used. In this case, we’re using the nginx image.
  • tag: This specifies the version of the Docker image. We’re using stable to ensure we’re using a stable version of Nginx.
  • pullPolicy: This determines how Kubernetes should pull the image. IfNotPresent means Kubernetes will only pull the image if it’s not already present on the node.
  • pullSecrets: If your Docker image is in a private repository, you’ll need to create a secret that contains your Docker credentials and reference it here. This field expects an array of secret names.
service:
  type: ClusterIP
  port: 80
  • type: This sets the type of the service. ClusterIP means that the service will be accessible only from within the Kubernetes cluster. Other possible values are NodePort and LoadBalancer, which expose the service to the outside world, but they should be used with care due to potential security implications. The preferred method for external access is through an Ingress controller below.
  • port: This property sets the port on which the service will be accessible. This should match the port that your application listens on.
ingress:
  enabled: true
  hosts:
    - host: chart-example.local
      paths: []
  • enabled: This property determines whether an Ingress resource should be created for the service. If set to true, the Helm chart will create an Ingress resource according to the other properties defined in this section.
  • host: This property defines the hostname to be used for routing traffic. In this case, any traffic intended for chart-example.local will be routed to the service by the Ingress.
  • paths: This property defines the paths for which the host should route traffic. An empty list, as shown here, means that all paths will be routed to the service. If you wanted to route only specific paths to the service, you could add those paths to this list. For example, paths: [“/api”, “/admin”] would route only traffic on the /api and /admin paths to the service.

In order for ingress.enabled: true to have effect, your Kubernetes cluster needs to have installed an Ingress Controller. One popular option is NGINX Ingress Controller, the official Quick start can be found here.

Optionally, for https certificate management you can install cert-manager. The Getting Started guide for NGINX-ingress can be found here.

If it’s not possible to set a DNS record to your cluster, or simply for development purposes, you can update /etc/hosts file with your IP address host mapping:

192.168.100.100 chart-example.local

Adding dependencies

Helm charts store their dependencies in ‘charts/’. But it is often easier to manage dependencies in ‘Chart.yaml’ which declares all dependencies. An example below:

dependencies:
- name: redis
  version: 16.13.2
  repository: https://charts.bitnami.com/bitnami
- name: mongodb
  version: 12.1.31
  repository: https://charts.bitnami.com/bitnami

Public charts can be found on Artifact Hub. Artifact Hub is for Helm charts as Docker Hub is for containers.

After setting the dependencies in Chart.yaml you need to run the following command that will pull the dependencies in the charts directory and set the Chart.lock:

$ helm dependency update

Dependencies can also have parameters in values.yaml. For example:

redis:
  fullnameOverride: redis
  architecture: standalone
  auth:
    enabled: false
mongodb:
  fullnameOverride: mongo
  architecture: standalone
  auth:
    enabled: false

The whole list of parameters are always found on the dependency Artifact Hub page, e.g. https://artifacthub.io/packages/helm/bitnami/mongodb for mongodb.

Validate the Helm Chart

Once you have completed modifying the Helm Chart, it’s crucial to ensure the chart is valid and well-structured. To do this, Helm provides a built-in linting tool which can be used to validate your chart. This tool checks for issues such as missing required fields, incorrect data types, and chart formatting.

You can run the linter by executing the following command in the directory containing your chart:

$ helm lint ./hello-world

If your chart passes the linting process, you’ll see an output message saying “1 chart(s) linted, 0 chart(s) failed”. If there are any issues, the linter will provide error messages detailing what needs to be fixed.

Deploy the Helm Chart

After validating the Helm Chart, the next step is to deploy the chart to your Kubernetes cluster. You can use the helm install command followed by a release name and the path to your chart. The release name is a unique identifier you assign to the deployment for tracking and managing it.

Here is the command for deploying the hello-world chart:

$ helm install hello-world-release ./hello-world

In the above command, hello-world-release is the release name and ./hello-world is the path to the chart.

After running this command, Helm will send the chart to your Kubernetes cluster, which then schedules the deployment of the application. You can check the status of the deployment using the Kubernetes command kubectl get pods. If everything is working correctly, you should see your pods running after a few moments.

You can check the release list using this command:

$ helm list

You can run the kubectl commands to check the deployment, services, and pods:

$ kubectl get deployment
$ kubectl get services
$ kubectl get configmap
$ kubectl get pods

Helm Upgrade and Rollback

Once your application is running, you might want to make changes or updates to your application’s configuration or to the application itself. Helm provides an easy way to upgrade your release with the helm upgrade command, which takes the release name and the path to the updated chart. Here is an example:

$ helm upgrade hello-world-release ./hello-world

If for any reason you need to revert your release to the previous version, Helm allows you to rollback to a previous revision using the helm rollback command followed by the release name and the revision number.

Here’s how you can rollback your hello-world-release to revision 1:

$ helm rollback hello-world-release 1

Uninstall The Helm Release

When you’re finished with your application, or if you want to redeploy it from scratch, Helm provides a way to delete the release with the helm uninstall command, followed by the release name. This command will remove the release from Helm’s management and delete all Kubernetes resources associated with the release.

Here’s how you can uninstall the hello-world-release:

$ helm uninstall hello-world-release

Remember, uninstalling a release will remove all of its resources from Kubernetes and they will not be recoverable. Make sure you have saved any data you want to keep before uninstalling a release.

More reading