Manage Kubernetes applications using Helm

The easy way.

Ravindra Singh
Xebia Engineering Blog
19 min readAug 31, 2019

--

Helm

Kubernetes is the most popular open source project on Github. It has captured the imagination of developers. Every other organisation is either in the process of moving their deployments to Kubernetes or planning to do in near future.

I remember when I started my journey with Kubernetes almost a year back, I was super excited about all this container orchestration thing. We started with 3–4 micro-services and our Jenkins pipelines had kubectl to deploy our Kubernetes resources. kubectl is a great tool to start with Kubernetes but as we moved along in our journey kubectl was not enough. We then started exploring Helm.

In this blog, I will get into details of Helm. We will start with what is Helm, why & how it can help you to manage our applications on Kubernetes.

I assume you have basic knowledge of Kubernetes resources like deployment, services etc and minikube. If not, then i would suggest to read below writing by Shekhar Gulati

https://medium.com/xebia-engineering/the-kubernetes-guide-for-java-developers-learn-kubernetes-by-deploying-a-real-world-application-35133f72d2e5

Let’s start by setting up the overall agenda for this post first:-

  1. What is Helm?
  2. How Helm works?
  3. Then, we will cover all the different use cases where helm can help
  4. And finally, we will create & deploy helm charts

Let’s get started!

Helm is a Cloud Native Computing Foundation incubating project. It is built by developers from Google, Microsoft, Samsung, and along with developers from many other organizations. It has a thriving community.

What is Helm?

Helm is a tool which helps to bind your Kubernetes resources into a bundle and then deploy it to Kubernetes cluster.

For example let’s suppose you have a Kava Microservice written in Spring Boot. The Kubernetes objects we will need are:

  • A deployment object
  • ConfigMap if you have any configuration data
  • A secret if there are any credentials required for this app
  • Kubernetes service of any type like NodePort, ClusterIp or Headless
  • Finally there can be other objects too according to your requirement like ingress, ServiceAccount etc

To keep things simple, we can assume we have three Kubernetes object — Deployment, ConfigMap, and a Service. These objects need to be in sync with each other, for example if Deployment object require some env variable name X from ConfigMap, then it is expected that ConfigMap have the value of X. In the same way Kubernetes services works upon label selectors. So if we have removed a label from deployment object, then same label should be removed form service object too. So, the point here is that Kubernetes objects for a particular service are dependent to each other.

But maintaining this dependency among Kubernetes objects becomes really tough when you have a lot of Kubernetes resources. It is almost impossible to keep track of every released object.

Here Helm comes to rescue by automatically packaging your app’s Kubernetes resources into one bundle called Helm Chart and deploy it on Kubernetes as a Helm Release with a specific revision number and chart version.

Helm gives everything necessary to keep track of your app’s deployment on Kubernetes.

I would sum up with saying that helm is packaging and deployment tool for kubernetes resources.

High level architecture of Helm

Now, that we have understood what is Helm and what it is offers. Let’s understand its high level architecture.

Helm is a client-server based tool. So there two main components in Helm architecture:

Helm Client:- Helm client is a command line tool and has to be installed on developer machine or Jenkins machine in case of CI/CD.

Helm client can be used to:-

  1. Create Helm chart for a Kubernetes application.
  2. Push/Pull helm charts to helm repositories(Helm repositories are like docker hub or Github where you can actually store your helm charts.)
  3. Interact with helm server(Tiller) to get information, deploy, uninstall, rollback a helm chart.

Helm Server(Tiller):- Tiller is a server side component of helm which is basically responsible to perform task asked by helm client.

Tiller is installed on Kubernetes cluster as a pod and require permissions to install and uninstall helm charts on the Kubernetes cluster.

Installation:- The best way to install helm client and tiller server is to follow instruction available on the Helm official website

Key terms in Helm

Helm Chart: Chart is basically bundle of all of the Kubernetes resources/objects for an application. This objects are written in YAML just like Kubernetes objects. But the values for the keys of YAML files can be configured from different configs or values.yaml files. What are the config of values.yaml files?

Helm Config/Values:- Kubernetes resources are written in YAML, which have key-values pair. So values for the different Kubernetes properties in Kubernetes resource definition vary by environments. For example in secret.yaml file , the database password for DEV environment will be different from UAT environment. So, config or values files are the files which contains the values or configuration data you need at the time of deployment of your helm chart.

We will see how we can configure our data for various Kubernetes objects with different value files.

Helm Release:- When you deploy your helm chart on Kubernetes cluster using helm client it will send the chart data which includes Kubernetes resources definition and values/config to tiller. Tiller will then deploy these resources to Kubernetes cluster. This deployed instance of your helm chart is called a release. Every helm chart release should have a unique name mostly similar to name of your application.

Helm Revision:- Whenever tiller deploy a release it gives it a revision number through which we can easily keep tracks of deployment of our helm chart.It is a counter which get incremented on every successful install/upgrade/rollback of your helm chart.

Chart version:- Every helm chart have a default chart version when you create a helm chart using helm client. And for best practice you should maintain the chart number of your helm chart whenever you modify your helm chart.

Now that we have fair idea about the Helm architecture and the key terms related , we can get our hands dirty by playing around with helm.

So I assume you have running minikube cluster on your machine and you have installed helm client and tiller using the instructions link i pasted earlier.

So lets start with a very basic command:-

Helm version command gives the version of helm client on your machine and and tiller installed Kubernetes cluster.

The helm ls command will give information about all the releases installed on your Kubernetes cluster. Since we have not installed any of the release using helm client it is giving blank results as of now.

Let’s learn Helm by using a hello-world application. I created a Github project that we will be using as our example use-case.

Let’s first understand what we have in this application. It is a simple example of Microservice architecture where in I have created two services.

  1. World -Service:- When you call this service on / address it will return a string as “world”
  2. Hello-Service:- When you call this service on / address it will return a string as “hello world” . This service actually makes a call to world-service and get message “world”. And append it will “hello” to return full sentence as “hello-world”. If it can not connect with world service then it return message as “World-Service is not reachable.”

Github repo includes the source for two Microservices and their corresponding Kubernetes resources. I will focus on the Kubernetes objects and helm charts only. There are all the instruction available to build these code using gradle in the README file.

Let’s explore the Kubernetes objects of each Microservices:

Hello-Service:- Hello service have 3 main k8s objects as deployment, ConfigMap, and service.

These are available at :-

Have a look at these three yaml files in above directory:-

deployment.yaml

configmap.yaml

service.yaml

As you can see in deployment.yaml file we have a deployment object which have two environment variables linked to the configmap. Configmap have the actual values for these environment variables. Then, we have service and label selector of service object have the exact same key-value pair that we have in the deployment template spec.

To deploy these objects on Kubernetes using kubectl:-

You can see all the 3 objects have been created.

Similarly you can deploy the world service too.

Let’s access these service using curl.

Get Minikube IP:-

Get the nodeport of our hello-service using kubectl.

NodePort of hello-service is 31087 and world-service is 31536.

So as you can see we are able to deploy our both microservices and are able able to access them using curl.

Now why we need helm?

So all these 3 Kubernetes resources we have deployed for each microservices have there own unique identity in Kubernetes and there is no such thing which picturize them to be together or linked to a single microservice. You can not even rollback to a specific version of your Kubernetes application because you do not have any version history. And what if let’s suppose the values in configmap differ by environment env for example the values of MESSAGE field in configmap of hello-service needs to be removed in dev env but should remain in UAT and PROD env.

All these problems can be solved if we bundle up our all the 3 Kubernetes resources and give them a single identity — helm release name, and keep track of the various deployed version by using Revision number. And as we discussed earlier Tiller does all this for you.

So let’s start by using helm to deploy and track our Microservices.

First let’s cleanup what we have done so far.

This will delete entire namespace along with all the resource we had deployed earlier and again create a fresh namespace.

Let’s create helm chart for hello-service:

This will create a default helm chart as below directory structure:-

We will not cover every little thing about this chart directory because my goal here is to enable you to create helm chart for your own applications but I would suggest to read https://helm.sh/docs/developing_charts/#charts and get know about everything about chart’s directory in detail.

If you go to templates directory, you will see four main files created there as below:-

So in the templates folder you put all your kubernetes resource files, like for our example we had three files for deployment, configmap and service. We don’t require ingress so we can delete this file. And since configmap file is not created by default so we will just create a configMap.yaml file with below content.

confgiMap.yaml

So now we have there main YAML files in template folder of our hello-service chart.

deployment.yaml

service.yaml

configMap.yaml

And all these have the default key-values pair created by helm only. So let’s just modify deployment and service files according to our requirement. We have our plane Kubernetes object definition in /kubernetes folder which we have deployed previously. So let’s just convert those into template files by taking values from {{ .values.* }} directives.

So the modified deployment and service files will look something like this:-

deployment.yaml

service.yaml

You must be wondering about things in {{ }} . So if you went through the guide about helm chart which i shared above then you must know the {{}} is template directive which is replaced by the values at the time of deployment of helm chart.

For example {{ .Release.Name }} will be replaced by the release name when you will deploy this helm chart. This we will see when we will deploy this helm chart. But i will recommend you go through that chart guide and know the basic details of helm chart.

Similarly {{ .Values }} refers the values from values.yaml file or the config file of your helm chart.

I have made a little advanced helm chart with basic k8s resource deployment, configmap, service, secret and horizontalautoscaler for both the microservices.

And i have created values.yaml file too. So if you check the values.yaml files for hello-service :-

So {{ .Values.deployment.name }} in the deployment file will be replaced by

at the time of deployment.

So if you need to rename you deployment at any point of time you just change it values in values.yaml file only.

You can create multiple values.yaml file for different environments like value-dev.yaml or values-uat.yaml etc.

So all the field in all the resources files with {{ .Values. }} have their corresponding values in the values.yaml file which is basic the config file of any helm release.

Now as we have helm chart ready with all the values in our values.yaml file. Let just deploy it.

Magic, isn’t it!

Let’s first understand the helm install command first.Although the detailed guide you can read at https://helm.sh/docs/helm/#helm-install and the basic thing which we have used above are as below:-

— name=hello-service :- This is how we give a release name to our release. Here hello-service is our release name.

— namespace=demo :- This is how we specify our namespace where all the resource has to be created.

-f hello-service/values.yaml :- This is the path from where {{ }} template directive will fill in all the values in our template files. As we can multiple values files so we can just provide required values files for different envs.

hello-service/ :- This is the path of our helm chart.

IF-Else in yaml files:- Let’s suppose you want some if else kind of things in the yaml files of your k8s resources. Helm template supports all these things too. For example in our case we have a resource called virtualservice.yaml, which is basiclly a istio resource, and we want it should be only installed if istio is enabled in our kubernetes cluster. So let’s have a look how we have enabled this requirement:-

So if you see the first line of virtualservice.yaml file it says if .Values.istio.enabled then only include the below block. And if you check the values of .Values.istio.enabled in values.yaml file :-

So at any point of time we can change it to true and redepoly it and next time virtualservice will be created along with all the other things.

This was one simple example of helm template, every one have their own different requirement and helm can used to implement them.

Anyways lets just deploy our world-service.

Now we have deployed both of the microservice using helm and we can access them using their nodeport.

Let’s use some basic helm commands to play with helm:-

helm ls

Now you can see their are two releases are deployed on our kubernetes cluster in demo namespace. And you can see their tracking details like revision, app version,chart version, deployed time etc.

helm upgrade

Let’s upgrade our world-service and change the message return from it from “world” to “world 2.0” . so our end goal is that when we will deploy 0.1.1 version of world service, then the actual message returned from world-servic ewill be “world 2.0” instead of “world”.

As the message is coming form env variable linked to the world-service secret and if we change the secret values from “ world” to “world 2.0” then it should work.

And if you check the secret.yaml file in template folder of helm chart. You will see that the value of MESSAGE if actually coming from {{ .Values.secret.data.message }} .

So we have to just change the value in values.yaml file as below:-

d29ybGQgMi4w is base64 encoded value of “world 2.0”.

And then deploy it again using helm with new values.

By this we have upgraded our world service and lets just check its revision number :-

Now you can see that revision number of world-service is 2.

Now just restart the world-service pod so that it can fetch new values of message env variable from secret. And hit nodeport of hello-service from browser or using curl.

As you can see response has been changed from “hello world” to “hello world 2.0”

helm rollback

Now let’s suppose you want to rollback you world-service to revision number 1 which has message as “world”.

that’s it!

You just have to give release name and the revision number on which you want to rollback.

Again restart the world-service pod and hit hello-service nodeport using curl.

it’s back to “hello-world”.

helm history

With this command you can check all the history of any release.

As you can see this command shows entire history if any release, it is showing when we have upgraded and when we have roll back our world-service.

So with this i think we have covered our agenda of this post let’s have a recap what we have done so far:-

  • We explored what is helm and it’s architecture
  • We explored various basic terminology about helm like chart,release and config.
  • We learned how we can create a helm chart and what a helm chart looks like.
  • Then we deployed two Microservices with their helm charts.
  • We explored how we can use helm template to perform logical operation in yaml files.
  • We then upgraded release and then again rollback it to previous version.
  • We checked history of one release.

Do comment your thoughts, queries or suggestion.

Happy Helming!

--

--

Ravindra Singh
Xebia Engineering Blog

Full Stack Developer |Spring Cloud|Spring Boot|Docker|Kubernetes|Istio