How to manage complex applications using Kubernetes-based Helm tool [Tutorial]

15 min read

Helm is a popular tool in the Kubernetes ecosystem that gives us a way of building packages (known as charts) of related Kubernetes objects that can be deployed in a cohesive way to a cluster. It also allows us to parameterize these packages, so they can be reused in different contexts and deployed to the varying environments that the services they provide might be needed in.

This article is an excerpt taken from the book Kubernetes on AWS written by Ed Robinson. In this book, you will discover how to utilize the power of Kubernetes to manage and update your applications. In this article, you will learn how to manage complex applications using Kubernetes-based Helm tool. You will start by learning how to install Helm and later on how to configure and package Helm charts.

Like Kubernetes, development of Helm is overseen by the Cloud Native Computing Foundation. As well as Helm (the package manager), the community maintains a repository of standard charts for a wide range of open source software you can install and run on your cluster. From the Jenkins CI server to MySQL or Prometheus, it’s simple to install and run complex deployments involving many underlying Kubernetes resources with Helm.

Installing Helm

If you have already set up your own Kubernetes cluster and have correctly configured kubectl on your machine, then it is simple to install Helm.

On macOS

On macOS, the simplest way to install the Helm client is with Homebrew:

$ brew install kubernetes-helm

On Linux and Windows

Every release of Helm includes prebuilt binaries for Linux, Windows, and macOS. Visit to download the version you need for your platform.

To install the client, simply unpack and copy the binary onto your path.

For example, on a Linux machine you might do the following:

$ tar -zxvf helm-v2.7.2-linux-amd64.tar.gz
$ mv linux-amd64/helm /usr/local/bin/helm

Installing Tiller

Once you have the Helm CLI tool installed on your machine, you can go about installing Helm’s server-side component, Tiller.

Helm uses the same configuration as kubectl, so start by checking which context you will be installing Tiller onto:

$ kubectl config current-context

Here, we will be installing Tiller into the cluster referenced by the Minikube context. In this case, this is exactly what we want. If your kubectl is not currently pointing to another cluster, you can quickly switch to the context you want to use like this:

$ kubectl config use-context minikube

If you are still not sure that you are using the correct context, take a quick look at the full config and check that the cluster server field is correct:

$ kubectl config view --minify=true

The minify flag removes any config not referenced by the current context. Once you are happy that the cluster that kubectl is connecting to is the correct one, we can set up Helm’s local environment and install Tiller on to your cluster:

$ helm init
$HELM_HOME has been configured at /Users/edwardrobinson/.helm.
Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.
Happy Helming!

We can use kubectl to check that Tiller is indeed running on our cluster:

$ kubectl -n kube-system get deploy -l app=helm
tiller-deploy   1         1         1            1           3m

Once we have verified that Tiller is correctly running on the cluster, let’s use the version command. This will validate that we are able to connect correctly to the API of the Tiller server and return the version number of both the CLI and the Tiller server:

$ helm version
Client: &version.Version{SemVer:"v2.7.2", GitCommit:"8478fb4fc723885b155c924d1c8c410b7a9444e6", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.7.2", GitCommit:"8478fb4fc723885b155c924d1c8c410b7a9444e6", GitTreeState:"clean"}

Installing a chart

Let’s start by installing an application by using one of the charts provided by the community.

You can discover applications that the community has produced Helm charts for at As well as making it simple to deploy a wide range of applications to your Kubernetes cluster, it’s a great resource for learning some of the best practices the community uses when packaging applications for Helm.

Helm charts can be stored in a repository, so it is simple to install them by name. By default, Helm is already configured to use one remote repository called Stable.

This makes it simple for us to try out some commonly used applications as soon as Helm is installed.

Before you install a chart, you will need to know three things:

  • The name of the chart you want to install
  • The name you will give to this release (If you omit this, Helm will create a random name for this release)
  • The namespace on the cluster you want to install the chart into (If you omit this, Helm will use the default namespace)

Helm calls each distinct installation of a particular chart a release. Each release has a unique name that is used if you later want to update, upgrade, or even remove a release from your cluster. Being able to install multiple instances of a chart onto a single cluster makes Helm a little bit different from how we think about traditional package managers that are tied to a single machine, and typically only allow one installation of a particular package at once. But once you have got used to the terminology, it is very simple to understand:

  • A chart is the package that contains all the information about how to install a particular application or tool to the cluster. You can think of it as a template that can be reused to create many different instances or releases of the packaged application or tool.
  • A release is a named installation of a chart to a particular cluster. By referring to a release by name, Helm can make upgrades to a particular release, updating the version of the installed tool, or making configuration changes.
  • A repository is an HTTP server storing charts along with an index file. When configured with the location of a repository, the Helm client can install a chart from that repository by downloading it and then making a new release.

Before you can install a chart onto your cluster, you need to make sure that Helm knows about the repository that you want to use. You can list the repositories that are currently in use by running the helm repo list command:

$ helm repo list

By default, Helm is configured with a repository named stable pointing at the community chart repository and local repository that points at a local address for testing your own local repository. (You need to be running helm serve for this.)

Adding a Helm repository to this list is simple with the helm repo add command. You can add my Helm repository that contains some example applications related to this book by running the following command:

$ helm repo add errm
"errm" has been added to your repositories

In order to pull the latest chart information from the configured repositories, you can run the following command:

$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "errm" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete.  Happy Helming!

Let’s start with one of the simplest applications available in my Helm repository, kubeslate. This provides some very basic information about your cluster, such as the version of Kubernetes you are running and the number of pods, deployments, and services in your cluster. We are going to start with this application, since it is very simple and doesn’t require any special configuration to run on Minikube, or indeed any other cluster.

Installing a chart from a repository on your cluster couldn’t be simpler:

$ helm install --name=my-slate errm/kubeslate

You should see a lot of output from the helm command.

Firstly, you will see some metadata about the release, such as its name, status, and namespace:

NAME:   my-slate
LAST DEPLOYED: Mon Mar 26 21:55:39 2018
NAMESPACE: default

Next, you should see some information about the resources that Helm has instructed Kubernetes to create on the cluster. As you can see, a single service and a single deployment have been created:

==> v1/Service
NAME                TYPE       CLUSTER-IP     PORT(S)  AGE
my-slate-kubeslate  ClusterIP  80/TCP   0s
==> v1/Deployment
my-slate-kubeslate  2        0        0           0          0s
==> v1/Pod(related)
NAME                                 READY  STATUS             AGE
my-slate-kubeslate-77bd7479cf-gckf8  0/1    ContainerCreating  0s
my-slate-kubeslate-77bd7479cf-vvlnz 0/1 ContainerCreating 0s

Finally, there is a section with some notes that have been provided by the chart’s author to give us some information about how to start using the application:


To access kubeslate.

  1. First start the kubectl proxy:

kubectl proxy

  1. Now open the following URL in your browser:


Please try reloading the page if you see ServiceUnavailable / no endpoints available for service, as pod creation might take a few moments.

Try following these instructions yourself and open Kubeslate in your browser:

Kubeslate deployed with Helm

Configuring a chart

When you use Helm to make a release of a chart, there are certain attributes that you might need to change or configuration you might need to provide. Luckily, Helm provides a standard way for users of a chart to override some or all of the configuration values.

In this section, we are going to look at how, as the user of a chart, you might go about supplying configuration to Helm. Later in the chapter, we are going to look at how you can create your own charts and use the configuration passed in to allow your chart to be customized.

When we invoke helm install, there are two ways we can provide configuration values: passing them as command-line arguments, or by providing a configuration file.

These configuration values are merged with the default values provided by a chart. This allows a chart author to provide a default configuration to allow users to get up and running quickly, but still allow users to tweak important settings, or enable advanced features.

Providing a single value to Helm on the command line is achieved by using the set flag. The kubeslate chart allows us to specify additional labels for the pod(s) that it launches using the podLabels variable. Let’s make a new release of the kubeslate chart, and then use the podLabels variable to add an additional hello label with the value world:

$ helm install --name labeled-slate --set podLabels.hello=world errm/kubeslate

Once you have run this command, you should be able to prove that the extra variable you passed to Helm did indeed result in the pods launched by Helm having the correct label. Using the kubectl get pods command with a label selector for the label we applied using Helm should return the pods that have just been launched with Helm:

$ kubectl get pods -l hello=world
NAME                                      READY     STATUS
labeled-slate-kubeslate-5b75b58cb-7jpfk   1/1       Running
labeled-slate-kubeslate-5b75b58cb-hcpgj   1/1       Running

As well as being able to pass a configuration to Helm when we create a new release, it is also possible to update the configuration in a pre-existing release using the upgrade command. When we use Helm to update a configuration, the process is much the same as when we updated deployment resources in the last chapter, and a lot of those considerations still apply if we want to avoid downtime in our services. For example, by launching multiple replicas of a service, we can avoid downtime, as a new version of a deployment configuration is rolled out.

Let’s also upgrade our original kubeslate release to include the same hello: world pod label that we applied to the second release. As you can see, the structure of the upgrade command is quite similar to the install command. But rather than specifying the name of the release with the --name flag, we pass it as the first argument. This is because when we install a chart to the cluster, the name of the release is optional. If we omit it, Helm will create a random name for the release. However, when performing an upgrade, we need to target a pre-existing release to upgrade, and thus this argument is mandatory:

$ helm upgrade my-slate --set podLabels.hello=world errm/kubeslate

If you now run helm ls, you should see that the release named my-slate has been upgraded to Revision 2. You can test that the deployment managed by this release has been upgraded to include this pod label by repeating our kubectl get command:

$ kubectl get pods -l hello=world
NAME                                      READY     STATUS
labeled-slate-kubeslate-5b75b58cb-7jpfk   1/1       Running
labeled-slate-kubeslate-5b75b58cb-hcpgj   1/1       Running
my-slate-kubeslate-5c8c4bc77-4g4l4        1/1       Running
my-slate-kubeslate-5c8c4bc77-7pdtf        1/1       Running

We can now see that four pods, two from each of our releases, now match the label selector we passed to kubectl get.

Passing variables on the command line with the set flag is convenient when we just want to provide values for a few variables. But when we want to pass more complex configurations, it can be simpler to provide the values as a file. Let’s prepare a configuration file to apply several labels to our kubeslate pods:

  hello: world 
  access: internal 
  users: admin

We can then use the helm command to apply this configuration file to our release:

$ helm upgrade labeled-slate -f values.yml errm/kubeslate

To learn how to create your own charts, head over to our book.

Packaging Helm charts

While we are developing our chart, it is simple to use the Helm CLI to deploy our chart straight from the local filesystem. However, Helm also allows you to create your own repository in order to share your charts.

A Helm repository is a collection of packaged Helm charts, plus an index stored in a particular directory structure on a standard HTTP web server.

Once you are happy with your chart, you will want to package it so it is ready to distribute in a Helm repository. This is simple to do with the helm package command. When you start to distribute your charts with a repository, versioning becomes important. The version number of a chart in a Helm repository needs to follow the SemVer 2 guidelines.

In order to build a packaged chart, start by checking that you have set an appropriate version number in Chart.yaml. If this is the first time you have packaged your chart, the default will be OK:

$ helm package version-app
Successfully packaged chart and saved it to: ~/helm-charts/version-app-0.1.0.tgz

You can test a packaged chart without uploading it to a repository by using the helm serve command. This command will serve all of the packaged charts found in the current directory and generate an index on the fly:

$ helm serve
Regenerating index. This may take a moment.
Now serving you on

You can now try installing your chart by using the local repository:

$ helm install local/version-app

You can test building an index

An Helm repository is just a collection of packaged charts stored in a directory. In order to discover and search the charts and versions available in a particular repository, the Helm client downloads a special index.yaml that includes metadata about each packaged chart and the location it can be downloaded from.

In order to generate this index file, we need to copy all the packaged charts that we want in our index to the same directory:

cp ~/helm-charts/version-app-0.1.0.tgz ~/helm-repo/

Then, in order to generate the index.yaml file, we use the helm repo index command. You will need to pass the root URL where the packaged charts will be served from. This could be the address of a web server, or on AWS, you might use a S3 bucket:

helm repo index ~/helm-repo --url

The chart index is quite a simple format, listing the name of each chart available, and then providing a list of each version available for each named chart. The index also includes a checksum in order to validate the download of charts from the repository:

apiVersion: v1 
  - apiVersion: v1 
    created: 2018-01-10T19:28:27.802896842Z 
    description: A Helm chart for Kubernetes 
    digest: 79aee8b48cab65f0d3693b98ae8234fe889b22815db87861e590276a657912c1 
    name: version-app 
    version: 0.1.0 
generated: 2018-01-10T19:28:27.802428278Z

The generated index.yaml file for our new chart repository.

Once we have created the index.yaml file, it is simply a question of copying your packaged charts and the index file to the host you have chosen to use. If you are using S3, this might look like this:

aws s3 sync ~/helm-repo s3://my-helm-repo-bucket

In order for Helm to be able to use your repository, your web server (or S3) needs to be correctly configured.
The web server needs to serve the index.yaml file with the correct content type header (text/yaml or text/x-yaml).
The charts need to be available at the URLs listed in the index.

Using your repository

Once you have set up the repository, you can configure Helm to use it:

helm repo add my-repo 
my-repo has been added to your repositories

When you add a repository, Helm validates that it can indeed connect to the URL given and download the index file.

You can check this by searching for your chart by using helm search:

$ helm search version-app 
NAME                  VERSION     DESCRIPTION 
my-repo/version-app   0.1.1       A Helm chart for Kubernetes

Thus, in this article you learned how to install Helm, configuring and packaging Helm charts.  It can be used for a wide range of scenarios where you want to deploy resources to a Kubernetes cluster, from providing a simple way for others to install an application you have written on their own clusters, to forming the cornerstone of an internal Platform as a Service within a larger organization.

To know more about how to configure your own charts using Helm and to know the organizational patterns for Helm, head over to our book, Kubernetes on AWS.

Read Next

Elastic launches Helm Charts (alpha) for faster deployment of Elasticsearch and Kibana to Kubernetes

Introducing ‘Quarkus’, a Kubernetes native Java framework for GraalVM & OpenJDK HotSpot

Pivotal and Heroku team up to create Cloud Native Buildpacks for Kubernetes