Kubernetes Deployments with Helm - Basic features

Kubernetes is a great tool for orchestrating all your containers in a microservices-based application. But managing all the YAML files (generically called manifests in the following) for deployments, configmaps, secrets, services etc. can quickly turn into a nightmare.

This is the point at which Helm, which calls itself “the package manager for Kubernetes”, comes to your rescue. In this first part of a multi-part blog post series, you’ll be introduced to the basic features & benefits of Helm.

What does Helm do?

Being a package manager, Helm provides a packaging format called chart. Charts bundle together the different manifest files that are required to deploy an application, e.g.

  • config-map.yaml
  • deployment.yaml
  • service.yaml

Instead of just bundling those manifest files in a package, Helm enables you to create templates within the chart, which are combined with default values from a file called values.yaml, and, optionally, additional values provided at installation time of the chart.

Like every good package manager, Helm also provides the functionality to install, upgrade and delete charts. By installing a chart into your Kubernetes cluster, you create a release. This is different from other package managers you might be familiar with, e.g. apt or dnf, but looking at the use case, it totally fits. When installing a .deb locally, you definitely want this package to exist only once on your machine. Installating an application like MySQL into your Kubernetes cluster, it’s not uncommon that you want to install multiple instances in parallel, each with a different configuration. Here, multiple releases created from the same chart, but with different values applied to the templates, solve the problem easily.

Use Cases

Speaking of use cases, there are two main usages of Helm charts.

The first is to utilize community charts, i.e. charts made publicly available for standard applications like MySQL, Prometheus or Jenkins. These charts enable a quick start to using these application within your cluster, often with sophisticated configuration options like clustering etc.

The second use case (and the one we at ePages mostly focus on) is to manage your own applications. For example we manage all of our microservice deployments with Helm charts. In this use case, you create your own charts for your own, mostly internal applications, but still benefit from the templating, value-override and installation features.

How it works

Helm consists of two parts, a command line client working locally on your machine (or on your CI/CD), surprisingly called helm, and a server-side component called tiller, which lives within your Kubernetes cluster.

Installation

To get started, simply download the latest Helm release from GitHub. Unpack the archive and add the helm binary to your PATH, and you’re ready to go.

For the installation of tiller, you need a running Kubernetes cluster and a KUBE_CONFIG pointing to the cluster you want it to be installed into (the latter is usually correctly set up when you can use kubectl on the cluster).

Once the prerequisites are fulfilled, just run

helm init

This way, helm will tell the Kubernetes API server to create a deployment for tiller, by default in the kube-system namespace (but this is configurable). Once the tiller pods are up & running, installing Helm is done and you can start creating releases in your cluster.

Installing a Chart (aka creating a Release)

Now that you’re all set, lets deploy your first application into your cluster using Helm:

helm install --name my-release --version 0.8.4 stable/grafana

With this command, you create a release named my-release using version 0.8.4 of the chart grafana from the chart repository with the alias stable. If you leave out the --name parameter, Helm will give your release a random name, which is nice for playing around, but definitely not something you want to use in production. When leaving out the version parameter, Helm will automatically pick the latest available version (it was only included in this example to support the upgrade in the next section). The chart repository stable has automatically been added to your local configuration when you ran “helm init”.

Congratulations, you just installed Grafana into your cluster with a single command! You can check the result with

helm list
kubectl get pods

Upgrading a Release

We just installed version 0.8.4 of the grafana chart, but as of the time of writing, the latest release is 0.8.5, let’s upgrade to this version:

helm upgrade --version 0.8.5 my-release stable/grafana

Easy, isn’t it?

Deleting a Release

If you finally want to get rid of a release, you can simply delete it:

helm delete my-release

This will delete the resources created by the release, but not the metadata about the release itself, which has the consequence that you cannot create a new release with the same name, as release names (obviously) need to be unique. If you want to get rid of all traces of your old release, just add the --purge parameter, and Helm will wipe out all traces of its existence.

Understanding Charts

Now that you’ve played around a bit with Helm and created your first release, it’s again time for some theory. Let’s have a closer look at what a chart actually is.

Technically, a chart is just a gzipped tar file containing a few mandatory, some optional standard files plus, also optional, additional custom files.

The best way to start is looking at a simple example, which you can easily create yourself using the following command:

helm create my-example-chart

This will create a folder structure like this:

my-example-chart/
  Chart.yaml
  charts/
  templates/
    NOTES.txt
    _helpers.tpl
    deployment.yaml
     ingress.yaml
    service.yaml
  values.yaml

Chart.yaml

The Chart.yaml file is one of two mandatory files in a chart. It contains the metadata that describe the chart. Let’s have a look at the Chart.yaml of our my-example-chart:

apiVersion: v1
description: A Helm chart for Kubernetes
name: my-example-chart
version: 0.1.0

The apiVersion is currently always fixed to v1. The description and name properties are pretty self-explaining, as well as the version. Versions of Helm charts mandatorily need to follow the SemVer 2 specification, i.e. they must consist of a MAJOR, MINOR and PATCH version part, delimited by dots. An additional pre-release version, e.g. rc1 could also be appended with a dash (-). Although SemVer versions can also include even more information (e.g. build info), those are not considered when determining version ordering.

In addition to the above mentioned ones, which are mandatory, the Chart.yaml could contain an arbitrary number of additional properties, some pre-defined, and whatever custom properties you need to describe your chart. Have a look at the docs for a detailed list of standard properties.

The charts folder

Charts can depend on other charts, i.e. include their templates and inherit from them. When you use these dependencies, the charts your current chart depends upon, will be placed in the charts folder, either automatically, when using Helm’s dependency management, or manually by the chart developer.

We’ll leave this topic out for the moment, and have a slightly closer look at it below when discussing the requirements.yaml.

The templates folder

The templates folder is where most of the “magic” of Helm happens. As expected, it mainly contains the actual templates for the manifests your application needs when being installed.

As templates are going to be the core of the second part of this short blog post series, I’m not going into any details here.

In addition to the template files for the manifests, there can be two other types of files in this folder: helpers and the NOTES.txt.

All files with a name beginning with an underscore (_) are considered helpers. They will not be rendered as part of the release, but contain template definitions which are used in various places. This makes them a kind of “template library”. Let’s have a look at one of the helpers generated by default as an example:


{{- define "my-example-chart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}

You can use the template function defined here in any manifest template you create, which highly reduces duplication. Please don’t care too much about the syntax for now, as we will have a much closer look at it in the next part.

The already mentioned NOTES.txt file is used for documentation purposes. It can contain template expressions and will be rendered to the command line after you installed the chart into your cluster. Its purpose is to help the users of your chart to find their way through the installed artifacts, and tell them how to use them.

values.yaml

The values.yaml in your chart is the second mandatory file. It contains the default values to be used in your templates, so they can (at least mostly) be rendered without the need to override values.

The content of the values.yaml is an arbitrary YAML structure, which you can define however you want, although there are some advices on how to structure them for ease of use that you will see in the next blog post.

# Default values for my-example-chart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
  repository: nginx
  tag: stable
  pullPolicy: IfNotPresent
service:
  name: nginx
  type: ClusterIP
  externalPort: 80
  internalPort: 80

requirements.yaml

When your chart gets more complicated, or the application you want to deploy consists of multiple components, then it’s time for a requirements.yaml. This file contains a list of other charts on which your chart depends. Let’s have a look at how dependencies are described in the file:

dependencies:
- name: apache
  version: 1.2.3
  repository: http://example.com/charts
- name: mysql
  version: 3.2.1
  repository: @stable

In this case, our application consists of at least two parts: an Apache web server, which will be deployed using the defined chart in version 1.2.3, and a MySQL database, using the corresponding chart in version 3.2.1. They are downloaded from different chart repositories, the first one defined by the actual URL, the second one by an alias stable, which you can define using the helm repo commands (see helm repo --help for details).

Other optional files

On top of the files and folders discussed so far, a chart can also contain additional files. Two of them can be considered “optional standard files” for documentation, and these are:

File name Description
LICENSE A plain text file containing the license for the chart
README.md A human-readable README file

Furthermore, you can also add any other file you need, e.g. files containing static data to be used within your templates, although this is (at least in my experience) not a very common requirement.

Outlook

So far, we’ve had a look at the basic features of Helm and got a high-level overview on how it works. You also learned about the structure of charts and how to create them. The next part of this series will show you how to write templates, how overriding values works, and provide some (hopefully) useful tips & tricks.

Stay tuned…