Authoring a Helm Chart on Kubernetes / AKS - Getting startedSolution ·
As we discussed in our last article, Helm is a great technology. I recommend using it not only to manage third party packages but also your own custom-developed solutions.
But how do you author a Helm Chart?
I found that question hard to answer. The common answer is “look at existing ones”. I have two problems with that:
- You'll be hit by complexity before you understand what a chart is so won't get very far.
- That sounds a lot like the old C / C++ makefiles: copy mine and modify it to fit your needs.
Now, if there’s a way to hate a technology and not want to use it, it is to have it rime with makefile. I don’t want that to happen to you, so, allow me to introduce you gently to Helm chart authoring.
In this article, we’ll author the simplest chart ever. The chart will deploy one Kubernetes resource: a namespace. It won’t contain any parameters, any dependent charts, tests or what have you. We will tour the world of Helm chart and run a bunch of commands to get familiar.
As usual, the code is on GitHub. There is also documentation out there. I recommend:
Both from the official Helm site. It is comprehensive. This article is shorter and simpler.
First you need to install Helm.
Helm comes as two components: Helm on the client side (e.g. your computer) and tiller on the cluster.
We recommend looking at either AKS documentation or Helm documentation for guidance.
Let’s get a few concepts out of the way.
From the official documentation, there are three big concepts we should be familiar with:
- A Chart is a Helm package. It contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster. Think of it like the Kubernetes equivalent of a Homebrew formula, an Apt dpkg, or a Yum RPM file.
- A Repository is the place where charts can be collected and shared. It’s like Perl’s CPAN archive or the Fedora Package Database, but for Kubernetes packages.
- A Release is an instance of a chart running in a Kubernetes cluster. One chart can often be installed many times into the same cluster. And each time it is installed, a new release is created. Consider a MySQL chart. If you want two databases running in your cluster, you can install that chart twice. Each one will have its own release, which will in turn have its own release name.
In short, a Chart is a Helm Package. A Release is chart deployed, with parameters (or values), on a cluster. It’s like an instance of a chart. A Repository is the central location where charts are collected and distributed. It’s like a Docker Repository but for charts (and way simpler). Azure Container Registry can be used as a Helm Repository.
So we have the following relationships:
A chart is an archive, a TGZ (i.e. TAR + GZIP) archive. It is composed of multiple files.
According to the official documentation, the file structure of a chart is the following:
<Chart Name>/ Chart.yaml # A YAML file containing information about the chart LICENSE # OPTIONAL: A plain text file containing the license for the chart README.md # OPTIONAL: A human-readable README file requirements.yaml # OPTIONAL: A YAML file listing dependencies for the chart values.yaml # The default configuration values for this chart charts/ # A directory containing any charts upon which this chart depends. templates/ # A directory of templates that, when combined with values, # will generate valid Kubernetes manifest files. templates/NOTES.txt # OPTIONAL: A plain text file containing short usage notes
We see there are a lot of optionals in there. This is why it’s easy to start.
Let’s look at our example at https://github.com/vplauzon/helm/tree/master/a-namespace. It has the following files:
a-namespace/ Chart.yaml README.md # Optional but quick to write values.yaml # Mandatory, but empty in our case templates/ namespace.yaml # The only resource this chart deploys: a namespace NOTES.txt # Optional but quick to write
As promised, this is pretty minimalist.
There really is content in only Chart.yaml and namespace.yaml, so let’s look at those.
Chart.yaml’s schema is defined in the official documentation. It contains a few mandatory fields and a lot of optional ones.
Our Chart.yaml is defined as follow:
apiVersion: v1 name: a-namespace version: 0.1.0 description: A simple example of a chart:: solely deploys a namespace keywords: - namespace - simple home: https://github.com/vplauzon/helm/tree/master/a-namespace sources: - https://github.com/vplauzon/helm/tree/master/a-namespace maintainers: # (optional) - name: Vincent-Philippe Lauzon email: NA url: http://vincentlauzon.com/
It stands in 14 lines. Let’s look at a few of them:
|1||apiVersion||Always v1: easy.|
|2||name||Name of the chart. It must match the folder name.|
|3||version||That's the package version. This will appear later when we list the Helm releases running on the Cluster.|
|5||keywords||Those are useful for feeding in the search (i.e. helm search command) within a repository|
The rest is purely informational.
In our case we have only one template: namespace.yaml. In general, there are many files in the template folder.
It is recommended practice to have one Kubernetes resource per template file.
namespace.yaml has the following content:
apiVersion: v1 kind: Namespace metadata: name: helm-deployed
This template is straightforward as there is no values. We’ll cover values in a future article. It is a simple namespace description.
When there are many files in the template folder, or even many resources in one file, the resources are sorted by kind and then alphabetic order for deployment.
Before we deploy our chart, let’s look at the current namespaces:
$ kubectl get namespaces NAME STATUS AGE default Active 4d kube-public Active 4d kube-system Active 4d
This is the typical configuration of a vanilla AKS cluster.
helm install is used to install a chart, i.e. create a release. We can install from different sources:
- Local folder (unpacked chart)
- Local archive (.tgz)
- Remote archive (i.e. URL)
- From repository
Let’s do the first one. Let’s clone the repo and position ourselves just above the a-namespace folder.
Now we can install by typing:
$ helm install a-namespace NAME: coiled-heron LAST DEPLOYED: Wed Oct 17 13:33:26 2018 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Namespace NAME AGE helm-deployed 0s NOTES: No values are supported. This is the most vanilla chart.
A couple of observations here:
- The name is generated as coiled-heron in our case ; this is random ; we'll see we can set the name
- The namespace is default ; this is the namespace where templates not specifying a namespace will be deployed (in our case it doesn't apply as we only deploy a namespace per se)
- It lists the resources that were deployed ; in our case helm-deployed namespace
- The NOTES section is the NOTES.txt file content
Now if we look at the cluster’s namespaces again:
$ kubectl get namespaces NAME STATUS AGE default Active 4d helm-deployed Active 1m kube-public Active 4d kube-system Active 4d
We observe the helm-deployed namespace that was just deployed.
Let’s look at the charts installed in the cluster:
$ helm list NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE coiled-heron 1 Wed Oct 17 13:33:26 2018 DEPLOYED a-namespace-0.1.0 default
We observe the following:
- The release name is there: coiled-heron
- The revision is 1 ; this isn't the chart's version, it is the release's revision
- The chart is a-namespace-0.1.0, which is a concatenation of the chart's name and version
At a glance we can see what is deployed on our system.
The revision is an integer incrementing at every update. It is used to track upgrades and rollbacks.
Let’s delete the release and confirm the namespace is gone:
$ helm delete coiled-heron release "coiled-heron" deleted $ kubectl get namespaces NAME STATUS AGE default Active 4d kube-public Active 4d kube-system Active 4d
Now, let’s reinstall the chart by given the release a name this time:
$ helm install --name myrelease a-namespace NAME: myrelease LAST DEPLOYED: Wed Oct 17 13:39:18 2018 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Namespace NAME AGE helm-deployed 0s NOTES: No values are supported. This is the most vanilla chart.
We can then find that release name in the list of releases as well:
$ helm list NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE myrelease 1 Wed Oct 17 13:39:18 2018 DEPLOYED a-namespace-0.1.0 default
helm list returns the list of deployed releases. Helm tracks deleted releases for audit purposes. We can see all releases, including deleted ones with:
$ helm list --all NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE coiled-heron 1 Wed Oct 17 13:33:26 2018 DELETED a-namespace-0.1.0 default myrelease 1 Wed Oct 17 13:39:18 2018 DEPLOYED a-namespace-0.1.0 default
Finally, we could package our chart:
$ helm package a-namespace/ Successfully packaged chart and saved it to: /home/vplauzon/git/helm/a-namespace-0.1.0.tgz
The created archive could then be uploaded to a repository (e.g. Azure Container Registry).
We did a quick getting started on Kubernetes Helm.
We saw the big concepts, the file structure, a very simple example and a couple of command lines.
Helm is quite easy to use and not so complicated to author. We hope this quick start will help you start authoring Helm charts for your projects!
Update (07-11-2018): See Authoring a Helm Chart on Kubernetes / AKS – Parametrized values on how to author charts with parameters.