In this post we will explain how we can use Helm for installing our application. In part 1 we will take a look how we can create a Helm Chart for our application and how to package it. In part 2 we will cover how to install the Helm package to a Kubernetes cluster, how to upgrade our Helm Chart and how to rollback our Helm Chart.

Create a Helm Chart

A prerequisite for what we are going to do in this post, is an installed Helm Client and Server (Tiller). We explained in a previous post how to do this.

We can create the required files for a Helm Chart manually, but the easiest way is to create it with the following Helm command where myhelmchartplanet is the name of your Helm Chart:

helm create myhelmchartplanet

This will generate a default directory structure with default files in it:

  • charts: a directory to configure dependencies to other charts. We will not use this in our post.
  • templates: a directory to configure Kubernetes, it contains templates which combined with the values.yaml will generate valid Kubernetes manifest files
    • deployment.yaml: the configuration yaml file for the Kubernetes deployment
    • ingress.yaml: the configuration yaml file for the Kubernetes ingress
    • NOTES.txt: a text file containing notes which will be printed after installation
    • service.yaml: the configuration yaml file for the Kubernetes service
  • Chart.yaml: the chart yaml file containing e.g. version information
  • README.md: a readme file with extra information about your chart, how to use it, which values can be adapted, and so on
  • values.yaml: the values to be used in your chart. The values are used in the templates files

We will push this configuration to a GitHub repository (see tag v0.1.0). Next step is to adapt the default files to our needs. The application we will package and deploy is a simple Spring Boot application which prints a hello message when accessing the /hello url. We used it before in a previous post and created a Docker image for it (we will use version 0.0.2-SNAPSHOT) which comes very handy at this moment.

Chart.yaml

So, first step is to adapt the Chart.yaml as follows:

apiVersion: v1 
appVersion: "0.0.2-SNAPSHOT" 
description: A Helm chart for Kubernetes 
name: myhelmchartplanet 
version: 0.1.0

Let’s take a look at the different items:

  • apiVersion: this is the Chart api version and should always have the value v1 (required)
  • appVersion: this is more informative and contains the version of the application which is contained in the package. In our case 0.0.2-SNAPSHOT. (optional)
  • description: a short description about the Chart (optional)
  • name: the name of the Chart (required)
  • version: the version of our Chart. As you can see, this is a different thing than the version of our application. They can be the same, but it is not required, they are independent of each other. The version number has to be in the SemVer 2 format (required).

With this configuration, our Helm Chart will be named myhelmchartplanet-0.1.0.

values.yaml

With the values.yaml file, we can adapt several values which are used in the Kubernetes templates files. We will change the following default values:

  • image.repository: the url where our Docker image can be found
  • image.tag: the tag of the Docker image we want to deploy
  • service.type: we change it to NodePort instead of ClusterIP in order to expose it outside our cluster, just like we did before
  • service.port: we set it to 8080, the port our application is using
  • service.nodePort: since we use the type NodePort, we also have to set the port to use

The values.yaml file has the following content after our adaptations:

replicaCount: 1

image:
    repository: mydeveloperplanet/mykubernetesplanet
    tag: 0.0.2-SNAPSHOT
    pullPolicy: IfNotPresent

nameOverride: ""
fullnameOverride: ""

service:
    type: NodePort
    port: 8080
    nodePort: 30036

ingress:
    enabled: false
    annotations: {}
    path: /
    hosts:
        - chart-example.local
    tls: []

resources: {}
nodeSelector: {}
tolerations: []
affinity: {}

service.yaml

Because we are using the service type NodePort, we have to change something to the service.yaml:

  • targetPort: the default value is http, we change it in order that the port of our application is being used
  • nodePort: we also have to define the property nodePort in order that our service sets it properly when being deployed to Kubernetes

Our adapted service.yaml is the following:

apiVersion: v1
kind: Service
metadata:
    name: {{ include "myHelmChartPlanet.fullname" . }}
    labels:
        app: {{ include "myHelmChartPlanet.name" . }}
        chart: {{ include "myHelmChartPlanet.chart" . }}
        release: {{ .Release.Name }}
        heritage: {{ .Release.Service }}
spec:
    type: {{ .Values.service.type }}
    ports:
        - port: {{ .Values.service.port }}
          targetPort: {{ .Values.service.port }}
          protocol: TCP
          name: http
          nodePort: {{ .Values.service.nodePort }}
    selector:
        app: {{ include "myHelmChartPlanet.name" . }}
        release: {{ .Release.Name }}

deployment.yaml

In the deployment file, we have to put the livenessProbe and readinessProbe in comments. These will check our application whether it is ready and alive, but we did not include the Spring Boot Actuator plugin in our application which will provide the url to check the readiness and liveness of our application.

Check the correctness of your chart

In order to check whether the changes you made to the different configuration files, you can issue the following command which will check the formatting and information:

helm lint myhelmchartplanet

I don’t know exactly what is being checked, but it once gave no issues when the deployment to Kubernetes went wrong. It is therefore not a complete check on a correct Kubernetes configuration. Just be aware of that.

Package the Helm Chart

Now that we have adapted the chart configuration to our needs and that we have pushed everything to a git repository, it is time to package our Helm Chart. Execute the following command from outside your git repository, the command will search for a directory with the name of the Helm Chart from where it is issued:

helm package myhelmchartplanet

The package is being created (a tar gz file) and the following respons is shown:

Successfully packaged chart and saved it to: /home/developer/myhelmchartplanet-0.1.0.tgz

As we said before, the name of our Helm Chart will be myhelmchartplanet-0.1.0 and here we can clearly see that.

Chart repository

Before we can install the Helm package we created, we must make it downloadable. This is done by means of a Chart Repository. A Chart Repository contains packaged Helm Charts. It is not much more than a website containing an index.yaml and the Helm packages. When you browse to your home directory to the directory .helm/repository/local, then you notice that our packaged Helm Chart is added to this directory. The index.yaml file is automatically updated and contains metadata about the packages. It looks like the following:

apiVersion: v1
entries:
  myhelmchartplanet:
  - apiVersion: v1
    appVersion: 0.0.2-SNAPSHOT
    created: 2018-09-16T14:51:02.933628266+02:00
    description: A Helm chart for Kubernetes
    digest: sha256:a9c44411c15b7aa980f1c2d2f8deb29a82fcbb98eebdfc4ccecbf0910bf8e051
    name: myhelmchartplanet
    urls:
    - http://127.0.0.1:8879/charts/myhelmchartplanet-0.1.0.tgz
    version: 0.1.0
generated: 2018-08-26T18:01:30.000450767+02:00

In a production environment you must ensure that your Helm packages are not stored on your local machine but are placed in a ‘real’ repository. E.g. Google Cloud Storage, Artifactory, GitHub Page or just an ordinary webserver.

Summary

In part 1 of this post we created our own Helm Chart, explained some of the files that are required, packaged our Helm Chart and made it available in a Chart repository. Next time we will continue with installing our Helm package to our Kubernetes cluster, upgrade it and execute a rollback.