Series "Helm Lightning Course"
Helm Templates and Values: Make Re-usable Helm Charts
In the previous lesson, we’ve written our first Helm chart and learned what charts and releases are. The only problem with this chart is that it’s static. It’s not too different from just having a YAML file applied with kubectl. The only benefit we get from using Helm is the release tracking and rollbacks. But Helm is much more than this and in this lesson we will learn about another core feature of Helm — templating.
Let’s start with the general idea of templates. Imagine you need to create a lot of very similar files — for example, PDF invitations to a party. Each PDF is more or less the same, the only difference being the name of the person that you want to invite.
To avoid creating each PDF from the scratch, you could create a special PDF file, that contains all the common content of the invitation, but leaves an empty area for the guest name. This file is a template.
To create a new invitation, you need to take the template of an invitation and input some information about the guest. This process of providing an information to the template and receiving a final document is called a template processing. In this situation, you become a template processor.
Templating in programming is not much different from what I just described, but, naturally, a bit more computer-oriented and a bit more powerful in terms of how complex your templates can be. Let’s get back to our PGAdmin Chart to see how templating works in Helm.
Extending the Chart
We have two templates in the
templates directory — for the Deployment and for the Service. We can ask Helm to render the final files from this templates by running
helm template . command. The output that you see here is exactly what Helm will apply to the Kubernetes cluster — when we run
helm install or
helm upgrade commands, Helm will first process the templates, and then send the result to the Kubernetes API.
Those are not really templates, because we never specified which parts of these files should change depending on our inputs. Let’s fix that. The first thing that I want to make dynamic is an environment label on each resource — I want to see if this resource belongs to the staging or to the production environment.
The way Helm templates can be made dynamic is by referencing “variable values”. If you’ve ever used Terraform, then Helm values are exactly the same concept as Terraform variables.
The variable can be referenced by the name like this:
We need to type two opening curly braces, then a special keyword “.Values”, then, after another dot, the name of the variable we want Helm to insert in this part of the template and, finally, two closing curly braces. The name of the variable can be anything you want. Let me now copy this label to few other places inside our templates.
Now let’s run
helm template again. We can see that the new label “env” is empty, because we did not set any value for our
env variable. There are multiple ways to do this.
We can supply values directly over the command line, with the set argument, followed by the variable name and the value:
helm template . --set env=staging
Now we see that the label got the proper value inside our template.
We can also create a special values file, and let Helm pick values from there. Let me create values.yaml file and define the env value in there. If I run
helm template again, I will see staging — this is because Helm Charts always load a file named values.yaml by default. I can create another values file, for example,
values.production.yaml and override env to be production. I can then specify this values file when running
helm template . --values values.production.yaml — Helm will load both values file, but the production one will win over the default one.
We can reference values anywhere inside the template file. Under the hood, Helm is using a templating processor from Go programming language, so most of the things Go templates can do, Helm can do as well. Let’s make the names of our resources dynamic, by adding env as a suffix. And now let’s run
helm template again. Now that names depend on the env variable, we can deploy this chart twice to the same Kubernetes namespace. I will deploy first the staging one, with default values - and then the production one... production one didn’t work, because of course I need to specify the production values file.
If we inspect the list of running pods, we will see two independent pgadmin pods.
Let’s extend our templates a bit more and use conditional statements. I want to run 2 replicas of pgadmin in production and only 1 replica in staging. To do this, I add a simple “if” statement in the deployment yaml, like this:
If equals Values.env and production, render replicas: 3, else render replicas: 1.
Now let’s render the template again. There are two weird empty lines, before and after the replicas. It won’t break our chart, but it would be nice to get rid of this. To do this, we need to add a minus sign after the opening curly braces — this way Helm template processors knows that it should not insert empty lines instead of
Let’s confirm empty lines are gone.
And now let’s upgrade our production chart again... and check the list of running pods - as expected, we have 3 production pods running.
Thanks to the power of Go templates, Helm charts become extremely flexible and powerful. We just saw the very basics of templating in Helm, but you can do much more complex things. It supports everything you would expect from a fully featured templating tool — loops, comparison operators, complex data structures, dozens of useful features as well as the way to define your own functions and helpers. The best source of information on all of this templating capabilities is the official documentation of Helm.
In the next lesson of this course, we will look at the more advanced example of using Helm — we will learn how to use third party Charts, including the dependency management between charts.
Here's the same article in video form for your convenience: