Packaged Kubernetes Deployments - Writing a Helm Chart

Navigate to:

Throughout my time at InfluxData, and even before, I have been working with containers, and occasionally doing useful things with them! This led me to try out Kubernetes, which I have found to be very useful. In my job, I end up having to deploy random code for things like internal dashboards, demos, reporting, and data collection. Much of this code lives on a small Kubernetes cluster that I maintain.

At first when I started running Kubernetes, I found that keeping track of all my *.yaml files to be a pain. Even though I had a repository where I would keep the current state of my deployments, it was a management nightmare. I would end up copying from old projects to get started with new ones, and keeping the repo up to date was a pain! I even wrote a quick little bash program to help with this.

Bottom line is that when you are running Kubernetes, you quickly get to a place where the management of your deployment files is cumbersome and often not using deployment best practices.

Enter helm.

Helm is a templating packaging and deployment manager for Kubernetes. Think of it like apt-get or brew for Kubernetes. It consists of a server that runs in your cluster and renders your templates, tiller, and a command line interface helm. (If you’re totally new to Helm charts, scroll to the bottom of this article for some handy reference content).

Through this experience, I thought it would make sense to develop a quick guide to writing a simple helm chart with a focus on workflow. If you want to follow along, download helm. Please note: A familiarity with Kubernetes and Docker is required.

1. Find an application to deploy

I’ll be deploying a small node app that has been sitting in my Github. WEC is a small nodejs application that subscribes to the Wikipedia Recent Changes feed. When it receives an event, it parses and inserts the event into an InfluxDB instance. I’m using the excellent node-influx/node-influx Javascript client to write to the database.

You can check out the code in /server.js.

2. Dockerize it!

When creating a helm chart, you first need an image to run. I’ve created a Dockerfile for this server. The next step is to push it to a Docker Registry that is accessible from your cluster. I use gcr.io because of its ease of use in Google Cloud. Other options are Docker Hub and Quay.io. You could also push to a private registry. To build and push the image from this repository run:

$ cd wec
$ export ORG=myorg
$ export REGISTRY=gcr.io
$ docker build -t $REGISTRY/$ORG/wec:latest .
$ docker push $REGISTRY/$ORG/wec:latest

3. Stub out helm chart

The helm cli has a command to stub out your chart. This makes getting projects started quick and easy. To create the chart files for WEC just run helm create wec. A directory, wec, will be created in the current directory with the following files:

$ tree wec/
wec/
??? Chart.yaml
??? charts
??? templates
?   ??? NOTES.txt
?   ??? _helpers.tpl
?   ??? deployment.yaml
?   ??? service.yaml
??? values.yaml

2 directories, 6 files
  • Chart.yaml contains metadata about the chart. You can use the defaults.
  • charts/ holds any dependency charts. You can delete this folder now. This is used when building a chart from component charts.
  • templates/ holds all of your template files! This is where you do your work.
  • values.yaml holds any variables you want to reference in your templates. These are the configuration options you present to the end user.

I’ve moved the chart into a directory called chart.

4. Write your .yaml files

Helm starts you off with a deployment.yaml and a service.yaml. If you need other types of Kubernetes objects in your chart the kubernetes/charts repo has some great examples:

Helm uses Golang templates as a tempting language. It will expand any variables in {{}}. As a chart author, you have some built-in objects available for reference in your chart files (e.g. {{ .Release.Namespace }}) as well as the values.yaml file (e.g. {{ .Values.database_name }}). There are two sets of template helper functions as well: Sprig and Golang template functions.

Conveniently, for wec we only require a deployment. wec subscribes to the Wikipedia feed and receives the data back without needing to expose an endpoint! Very easy! We will need to set a couple of ENV as well to point to the database, other than that the stock file looks the same. We want to make those database connection parameters available in the values.yaml file to make database configuration easy. Here is our deployment file:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  # Template helpers are stored in /templates/_helpers.yaml
  name: {{ template "fullname" . }}
  labels:
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    metadata:
      labels:
        app: {{ template "fullname" . }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        env: 
        - name: DATABSE_NAME
          # `quote`-ing strings prevents type errors on yaml parsing
          value: {{ .Values.database_name | quote }}
        - name: INFLUX_URL
          value: {{ .Values.influx_url | quote }}
        - name: INFLUX_PORT
          value: {{ .Values.influx_port | quote }}
        - name: BATCH_SIZE
          value: {{ .Values.batch_size | quote }}
        - name: CONNECTION_URL
          value: {{ .Values.connection_url | quote }}

And the default values.yaml:

replicaCount: 1
image:
repository: gcr.io/influx-perf-testing/wec
tag: latest
pullPolicy: Always
database_name: 'wikipedia'
influx_url: "db-influxdb.prod"
influx_port: "8086"
batch_size: 10
connection_url: 'https://stream.wikimedia.org/rc'

5. Test your chart

Now that we have written a chart, we need to see if it produces the proper result. Luckily helm has some utilities to help with this. To see the deployment files that will be output by helm, run the following command:

$ helm install --dry-run --debug --name test --namespace test chart/wec/

This debug output is very helpful in chart development and is a great way to inspect the output of your chart and check for any errors before trying to install it on your cluster.

Tip: If you run helm install without --dry-run --debug and your chart errors out sometimes there is a ghost release left. You can delete image by passing the --purge option to helm delete {{ .Release.Name }}.

6. Deploy it!

When you are ready to deploy your chart just run helm install --name wec --namespace wec ./chart/wec/ to install!

When you run the install, you should see the output of NOTES.txt. This should give instructions on how to health check, or interact with the deployment:

$ helm install --name wec --namespace wec ./chart/wec/
NAME: foo
LAST DEPLOYED: Fri Mar 10 09:04:37 2017
NAMESPACE: bar
STATUS: DEPLOYED

RESOURCES:
==> extensions/v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
foo-wec 1 1 1 0 0s

NOTES:
Watch for you pods to come up by running the following command:

- kubectl get pods --namespace bar -l app=foo-wec -w

Check the logs on a running pod with the following:

- kubectl logs $(kubectl get pods --namespace bar -l app=foo-wec -o jsonpath='{ .items[0].metadata.name }')

Once the deployment is running you should be able to see the events flowing into your InfluxDB instance. Then you can have fun exploring the data! Here is a graph of the number of bot vs human edits on Wikipedia (the humans are winning - for now):

7. Next steps

This guide just scratches the surface of helm charts. Helm also offers hooks to enable running jobs at different points in chart lifecycle. There is also an excellent tips and tricks guide for debugging common issues. And packaging charts for distribution and building chart repos could be another blog post in and of itself. If you have further questions, the helm community is active on the Kubernetes slack in the helm channel.

If you are interested in experimenting more with the InfluxData stack, we have charts for all of our products available in the main charts repo:

For those of you who are just beginning with Helm charts, here are some answers to basic questions about how Helm charts work.

What is a helm chart?

Helm is designed to help you manage all of your Kubernetes applications in one simple, easy-to-use place — and Helm charts are a big part of what helps you define, install and upgrade even the most complicated applications you happen to be working with. A chart is little more than a collection of files that describe a related grouping of Kubernetes resources.

The directory name of the Kubernetes Helm chart in question will just be the name of the chart itself, without any type of versioning information. Inside that directory, Helm will create a structure that includes all listed file names. One of those will be the Chart.yaml file, which is required for a chart to properly function. Here, you’ll find important information like the name of the chart, the API version, the SemVer 2 version, a list of keywords about the project and more. You can also include other optional information like URLs for the source code of the project, the name and other contact information of the person maintaining the project and more.

Why are Helm charts used?

By design, Kubernetes Helm charts make it easy to create, version, share and publish your applications. It’s also built to support workflows that are far more advanced than you can complete with simple copying and pasting alone. A single chart might be used to deploy something simple, or something far more complex like a web app stack complete with servers, caches and more.

Overall, Helm charts are created as files that are laid out in a very particular type of directory tree that makes sense given the project you’re working on at the time. They can then be packaged into archives depending on the most recently updated version, at which point they can be deployed in any way you see fit.

How to create a Helm chart

The process of creating a Helm chart is very straightforward — you can do so right from the command line. All you have to do is use the following command:

  • helm create [insert name here]

This single command will create a chart directory, along with all of the different common files and directories that are to be used within the chart. But most importantly, that final portion of the command will be the given name for everything that comes after. So if you wanted to create a Helm chart with the name of the project you’re currently working on, you would include it as the last portion of the command prior to execution.

How do I update a deployed helm chart?

Whenever a new version of a particular Helm chart is released, or if you want to make any changes to the configuration of the current release, you can always use the following command:

  • helm upgrade

This will take your existing release and upgrade everything according to only the information you provide. It’s also important to note that because Kubernetes charts by nature can be incredibly large and complex, Helm will always try to perform the most straightforward upgrade possible. This means that it will update the things that have changed since the last release whenever you run that command. Because of this, Helm chart updates will happen far faster than you likely expect.

Note that if you’re unhappy with any updates and would like to roll back to a previous version, you can also do so using the following command:

  • helm rollback

What is the anatomy of a helm chart?

While the internal structure of your Helm chart will obviously vary depending on the deployment, any Helm chart tree will contain the aforementioned .yaml file, template files and a notes.txt file. The notes.txt file in particular will always print on the command line whenever you start your application.

How to create a helm chart from a docker image

After you have obtained the appropriate application source code and have built your docker image, the process of creating a new Helm chart from that image is straightforward. All you have to do is publish the image and use the “helm create” command. Then, you can edit the values.yaml file and edit the deployment.yaml file as you see fit to include your own variables.

Note that to publish your docker image, you will need to upload it to a public registry. Just a few of the options that you can choose from include Google Container Registry, Amazon EC2 Container Registry, Azure Container Registry, Quay and, of course, Docker Hub. Simply log into your public registry of choice and publish the image to your account. Once you have confirmed that the image is in your account and is visible on your dashboard, you can continue with the rest of the process.

How to deploy a helm chart in Kubernetes

Once you have connected to your Kubernetes cluster, you can deploy your Helm chart using the following command:

  • helm install [INSERT NAME HERE] ./helm-chart/go-k8s/

You should replace the [INSERT NAME HERE] placeholder with the name of your actual Helm chart release. Once the Helm chart has been deployed, you’ll be able to gather a lot of useful information about the chart itself that you can use to better manage your projects moving forward. Once you’ve properly configured your database, you’ll also be able to access your application and continue to work on it.