Helm - the Package Manager for Kubernetes - Part 2

04.03.2021 Stefan Welsch
Cloud DevOps helm cicd iac k8s handson


In the first part we saw where to find an existing chart (Helm Hub) and how to install it on a Kubernetes cluster. We looked at how you can transfer your own configurations to the chart and how to upgrade and rollback. Today we want to go one step further and see how you can create your own chart.

Building a chart

First, let's take a look at how a helm chart is structured. The easiest way to do this is to create our own chart. Helm gives us a simple command that we can use to create the skeleton of our own chart.

~ ❯ helm create mychart
Creating mychart

Let's see what happened. A folder has been created in which the required configurations are located.

~ ❯ ls mychart
Chart.yaml  charts      templates   values.yaml


This file contains the metadata of the chart, such as name, description, type and version. ApiVersion must always be set and is “v2” for Helm 3.

~/mychart ❯ cat Chart.yaml
apiVersion: v2
name: mychart
description: A Helm chart for Kubernetes

# A chart can be either an 'application' or a 'library' chart.
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"

Directory: charts

This directory is empty. Here we have the option of adding existing charts that are required for our chart, i.e. dependencies. Another way to add dependencies, preferred by Helm, is as a dependencies field in the Chart.yaml file. We can add dependencies here and then download these dependencies into the charts folder with the command helm dependency update.

For our simple example we don't need this function for now.

  - name: apache
    version: 1.2.3
    repository: http://example.com/charts
  - name: mysql
    version: 3.2.1
    repository: http://another.example.com/charts

Further information can be found on Helm page.

Directory: templates

Now we come to the heart of our chart. All configuration files that we need for the installation on the Kubernetes cluster can be found in this directory. All files that are in the templates directory are sent through the Helm Template Rendering Engine. The results of the templates are collected and then sent to Kubernetes.

~/mychart ❯ ls templates
NOTES.txt           _helpers.tpl        deployment.yaml     hpa.yaml            ingress.yaml        service.yaml        serviceaccount.yaml tests

Here we see various files that Helm has already created for us.

  • NOTES.txt

    • This is the help text for a chart. This is displayed to the user when he runs helm install
  • deployment.yaml,service.yaml,hpa.yaml,ingress.yaml,serviceaccount.yaml:

    • Basic framework to create a Kubernetes resource
  • _helpers.tpl:

    • Here are helpers for templates that can be reused in the chart.
  • tests:

    • Here are tests to verify the functionality of the chart in the cluster.


The values.yaml file is important to parse the templates. All default values are located here, which can be overwritten by the user with helm install or helm upgrade.

With this knowledge we can now develop our first own chart.

The first own chart

Let's start with a simple example. To do this, we first delete all files in the templates folder so that we can start our little tutorial from scratch.

rm -rf mychart/templates/* 

Then we create our first own template. We create a file named configmap.yaml with the following content:

apiVersion: v1
kind: ConfigMap
  name: {{ .Release.Name }}-configmap
  name: {{.Values.myName}}

We now have an unknown syntax in the file.

{{ .Release.Name }} and {{.Values.myName}}. Both are special placeholders that are replaced by the template rendering engine.

As the name suggests, {{ .Release.Name }} is dynamically replaced by the name of the release that we specify when installing.

{{.Values.myName}} is replaced by the property myName from the file values.yaml. Let's take a closer look at this file.

myName: b-nova

Now we already have a fully executable and installable chart. Let's see what happens during the installation. To do this, we can append the flag --dry-run to the install command to simulate the installation. With --debug we activate “verbose” output.

~ ❯ helm install myRelease ./mychart --dry-run --debug
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: ~/mychart

NAME: myRelease
LAST DEPLOYED: Thu Feb  4 19:07:54 2021
NAMESPACE: default
STATUS: pending-install

myName: b-nova

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
  name: myRelease-configmap # <-- {{ .Release.Name }}
  name: b-nova # <-- {{.Values.myName}}

As we can see, our placeholders have been replaced as requested. Now we can install our chart. However, we don't want to use the default name “b-nova” during the installation, we want to assign a name of our own. We have already seen above that we can overwrite the values by specifying our own values.yaml file, or by using the --set flag during installation. We want to try the second variant at this point.

~ ❯ helm install bnova-chart ./mychart --debug --set myName=whats_my_name
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: /Users/swelsch/mychart

client.go:122: [debug] creating 1 resource(s)
NAME: bnova-chart
LAST DEPLOYED: Thu Feb  4 19:18:16 2021
NAMESPACE: default
STATUS: deployed
myName: whats_my_name

myName: whats_my_name

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
  name: bnova-chart-configmap
  name: whats_my_name

Success! The chart was successfully installed and the default name was replaced with the dynamic value. Now we want to verify again whether our ConfigMap was really deployed correctly. So we look directly on the cluster with kubectl.

~/mychart ❯ kubectl get configmap
NAME                    DATA   AGE
bnova-chart-configmap   1      4m40s

As we can see, the ConfigMap was created with the correct name. Let's also take a look at the content for completeness.

~/mychart ❯ kubectl describe configmap bnova-chart-configmap
Name:         bnova-chart-configmap
Namespace:    default
Labels:       app.kubernetes.io/managed-by=Helm
Annotations:  meta.helm.sh/release-name: bnova-chart
              meta.helm.sh/release-namespace: default

# Data
Events:  <none>

You can find the entire code in the b-nova Github.

The content also corresponds to the expected result. We have successfully created our first chart and installed it on our cluster.

Next steps:

Helm Charts has a great future in the managed container environment. We will therefore be eager to follow the development of Helm. In the next TechUp I want to look at the following topics with you using a practical example:

  • Monocular - the front end for helms

  • Host your own repository

  • Template:

    • Template functions and pipelines

    • flow control

    • Built-In Objects

    • Named templates

    • subcharts

    • Debugging Templates

    • Post rendering

    • File handling

  • Best practices

Have fun and stay tuned!

This text was automatically translated with our golang markdown translator.

Stefan Welsch - pioneer, stuntman, mentor. As the founder of b-nova, Stefan is always looking for new and promising fields of development. He is a pragmatist through and through and therefore prefers to write articles that are as close as possible to real-world scenarios.