What is Helm? Helm is a package manager for Kubernetes that makes it easy to take applications and services that are either highly repeatable or used in multiple scenarios and deploy them to a typical K8s cluster.
This instalment of our Kubernetes consulting blog series is based on IBM’s explanation, which you can also watch here:
To understand better the role Helm plays, let’s take a look at a typical scenario of applications and services being deployed to Kubernetes.
How Helm works with Kubernetes
Let’s take an example of an ecommerce platform. Big ecommerce platforms typically have a marketing push and attempt to sign up new users ahead of the winter holiday season.
Let’s say we’ve written a Node.js application we are going to deploy to our Kubernetes cluster. Because it needs to be highly available for the particularly busy period coming up, we have created two replicas of the application to be able to handle all the requests coming in.
Beneath the two Node.js applications, we’ve got a MongoDB database. That’s going to handle the communication to and from each of the application replicas.
In this example, we’ve also written a service as a way to access our application, and we’ve written it as a node port. A node port means that there’s a 1-to-1 ratio between IPs inside and outside of our Kubernetes cluster.
- JS application in 2 replicas
- MongoDB database
- Node port service
To deploy the kind of application stack described, it needs to be defined. One way to define the stack with Kubernetes is to write a couple of YAML files to describe things like:
- What the deployments are going to look like
- What the service is going to look like
Let’s look at some of the key elements in a parsed down example.
With the deployment of the Node.js application, along with MongoDB, we know we’re going to be writing an image of Node and Mongo. That means our YAML file should look something like:
We decided our service would be a type of node port. So that’s going to be written like:
This is a 1-to-1 ratio between IPs inside and outside of our service, to be able to route it to just one service on our deployment because we have 2 replicas to mitigate load whenever it comes to our deployment.
Let’s say for this particular example, the deployment is going to be served up on port 8080. We can write than into our service.YAML file.
If we’ve written the application and YAML files ourself and are familiar with the configurations, making changes and updates if requirements change should be fairly easy, as long as we are still working on the application.
If we want to spin the application down at the end of the holiday season, reducing additional replicas of the application no longer required due to reduced demand, we know exactly where to find the number of replicas and make the change.
But what if we’ve moved on to a new job or project and someone else now has to pick up where we left off with the example application stack? They may not know where to go to change the number of replicas of the particular application.
It would be great if there was an easier way to manage the configuration of a whole application stack. And separate that logically from everything related to the particular templated application.
Helm – Kubernetes’s package manager
That’s where Helm comes in. It can be thought of as combining two particular components for a whole application stack:
- A configuration – defined by our Values.YAML file.
- A template – which is called a ‘chart’ in Helm.
The Helm chart consists of all the files we’re going to be templating on the left of the diagram.
But how do we actually template these files and inject variables into them? We take our configuration and instead use templating language to decide where those values are going to be put inside our template, or chart.
Let’s say we want the number of replicas to be determined by our configuration instead of hardcoded into a particular deployment.YAML file. We can say replicas will instead be managed by values.deployments.replicas.
We’re now going to refer to the values.deployment.replicas node, which is much easier to find in the configuration. This means that depending on what we want to be hardcoded in our template, we could decide to keep things there, or simply reference them in the Values.YAML.
We can do the same thing for our service. If we want to switch from a node port to load balancer as given by Kubernetes in the future, we could change:
For:
That means for a developer working on the project, or someone working in infrastructure making sure it’s deployed fresh, they can simply change the configuration here:
How Helm injects templated configurations into Kubernetes in a way the cluster understands
How do we combine all of the below into our Kubernetes cluster?
If we want to combine this all into one Helm chart, we simply write something like – helm install myApp – when installing the Helm CLI onto our machine.
Helm then takes the templating chart that’s been created, look for the parts where variables in the configuration have been defined. It will then go to the configuration file, use YAML to find the nodes needed, and inject those parameters inside the templating file.
Once everything has been comprised by Helm, it will send those over to the Kubernetes cluster. Until Helm 3 was released in 2019, the comprised templating file was sent over to Tiller, a component that needed to be installed on the Kubernetes cluster. Tiller was like the server-side component of Helm. It took the commands sent by the Helm client and turned them into something the Kubernetes cluster would understand.
Why has Tiller been removed from Helm 3?
Helm 2 was highly dependent on Tiller for translating a chart life-cycle into a format Kubernetes understood. But Tiller was cut out of Helm 3.
Tiller came with security issues and running it in production meant it had to be carefully secured. That added additional learning steps for the DevOps. In Helm 3, security management is left to Kubernetes to maintain and Helm can focus on package-management. Which also reduces the burden on DevOps.
Helm particularly useful if we want to upgrade from a configuration or rollback
In our ecommerce application example, once we’re past the holiday season and want to spin down to just one replica, we don’t need to take down the application and redeploy it with the new configuration. We can simply write:
Helm upgrade MyApp
Helm again templates everything out, makes sure it works the way it’s supposed to and sends to configuration over to Kubernetes, so it can manage uptime as the most important characteristic of the particular stack.
What if we make a mistake when upgrading and something we changed doesn’t work? We simply give Helm the ‘roll back’ command. Helm keeps a version history of different configurations that have been sent over it into Kubernetes. That means we can roll back to the last known working configuration whenever such a step might be required.
Helm Repos
We can deploy Helm charts in a repo with the command:
Helm package
We then use the Helm repo index to send it up to the repository. That means the same Helm charts can be used by anyone else who may need to in future.
Using Helm with Kubernetes improves package management, app upgrade efficiency and team collaboration
By parameterising a hardcoded YAML with Helm, it’s easier to manage packages and upgrade or roll them back when needed. Helm also makes it easier and more accessible for everyone else on a team to understand what’s going on, where to find and alter variables, and to make use of charts already in the repo.
Further learning on Helm and Kubernetes
This blog post is inspired by the introductory explanation of Helm’s role in Kubernetes provided by IBM through the YouTube video linked to here. For anyone interested in a more detailed, but still introductory guide to Helm, IBM also offers a great, concise course on the fundamentals of Helm.