Easier Kubernetes Deployments with Helm3 & ChartMuseusm
Photo by Igor Miske on Unsplash

Easier Kubernetes Deployments with Helm3 & ChartMuseusm

Helm is a package manager for Kubernetes. It helps you define, install, and upgrade even the most complex Kubernetes application. Helm is a graduated project in the CNCF and is maintained by the Helm community. It has been around for some time now. Recently the v3 was released which has the tiller removed and made Helm more flexible and user friendly. Helm can be used to:

  • create, share, and host your own packages
  • install packages and query any k8s cluster to see what packages are installed and running (The Helm Community provides 800+ Helm charts!)
  • upgrade, delete, rollback, or view the history of installed packages

This article is an introduction to what is Helm and what it can do for you and how to store the Helm packages on a repository provided by Chartmuseum.

Prerequisites

You should have access to a Kubernetes cluster and have a local configured kubectl. For the latest release of Helm, it is recommended to have the latest stable release of Kubernetes, which in most cases is the second-latest minor release. You should also be confident with Kubernetes Objects

You should also install Helm which can be done using tools like homebrew on a Mac. Follow the installation guide on the Helm documentation page.

Introduction

The Kubernetes Objects of an application are defined in separate YAML files, and with the kubectl command line tool are deployed on a cluster.

A Helm chart encapsulates each of these YAML definitions, provides a mechanism for configuration at deploy-time, and allows you to define metadata and documentation that might be useful when sharing the package.

Creating a chart

The helm create command is the best way to bootstrap your first chart. It creates the directory structure and files you can then build on.

$ helm create mychart

$ tree ./mychart
./mychart
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml


3 directories, 9 files

The most important part of a chart is the templates directory. You can edit or replace the files in that directory with your own. In this directory, you can create subdirectories which will also be processed by Helm. In the end, you will have a working chart that can be deployed using the helm install command.

Helm uses the Go template rendering engine to process those templates. If we take a look at the service.yaml in the templates directory you will almost immediately note special tags that Helm will use to generate a valid Service YAML.

apiVersion: v1
kind: Service
metadata:
  name: {{ include "mychart.fullname" . }}
  labels:
    {{- include "mychart.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "mychart.selectorLabels" . | nindent 4 }}}

Now if we run helm install with the --dry-run flag we will notice that the produced service.yaml file has all the labels populated, the port and selector configured:

$ helm install --generate-name --dry-run --debug ./mychart
...

---
# Source: mychart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: mychart-1588661695
  labels:
    helm.sh/chart: mychart-0.1.0
    app.kubernetes.io/name: mychart
    app.kubernetes.io/instance: mychart-1588661695
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: mychart
    app.kubernetes.io/instance: mychart-1588661695

---
...

The Helm-specific object .Chart is used to provide the metadata about the chart to the definitions such as name, or version. The .Values is used to expose configuration that can be set at the time of deployment. The defaults are defined in the values.yaml file provided with the chart.

Now if we change in the values.yaml file the port of the Service definition and run again the helm install with dry-run we will find the targetPort in the Service and containerPort in the Deployment changed to the value you specified. The use of templating can greatly reduce boilerplate and simplify your definitions.

The user of the chart could override the values with a command like this:

$ helm install --generate-name --dry-run --debug ./mychart --set service.port=8080

...
---
# Source: mychart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
...
spec:
  type: ClusterIP
  ports:
    - port: 8080
      targetPort: http
      protocol: TCP
      name: http
  selector:
...

The partials and functions defined in _helpers.tpl are also used in the service.yaml. You should take a look at the Helm Chart Template Guide for detailed reference on how to use functions, partials, and flow control when developing a chart.

The NOTES.txt file is a templated, plaintext file that gets printed out after the chart is successfully deployed. It is commonly used to describe the next steps for using a chart. NOTES.txt is run through the template engine so you can use templating to print out working commands for obtaining an IP address, or getting a password from a Secret object etc.

Deploying

Let's try to deploy this chart on a Kubernetes cluster with:

$ helm install example ./mychart --set service.type=NodePort

NAME: example
LAST DEPLOYED: Tue May  5 09:36:31 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services example-mychart)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")

  echo http://$NODE_IP:$NODE_PORT

The output of helm install displays a summary of the state of the release, what objects were created, and the rendered NOTES.txt file to explain what to do next.

Now let's run the commands in the output to get a URL to access the NGINX service and open it in our browser and see the NGINX welcome page.

No alt text provided for this image

To delete the Helm chart from the k8s cluster we just run:

$ helm delete example

release "example" uninstalled

Packaging

Now that we have a working chart we can package it to be able to share it. We've been using the local, unpackaged chart so far and the helm install command to run it. The Helm package is just a gzipped tar of our directory. We can package our example chart like this:

$ helm package ./mychart

Successfully packaged chart and saved it to: /Users/sosic/projects/mychart-0.1.0.tgz

To install the chart via Helm package we run:

$ helm install example mychart-0.1.0.tgz --set service.type=NodePort

NAME: example
LAST DEPLOYED: Tue May  5 09:57:42 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services example-mychart)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath=
"{.items[0].status.addresses[0].address}")

  echo http://$NODE_IP:$NODE_PORT

Chartmuseum

We now have a highly customized chart ready. The only thing that remains is to distribute it on repositories. That's where Chartmuseum comes to action.

ChartMuseum is an open-source Helm Chart Repository written in Go (Golang), with support for cloud storage backends, including Google Cloud Storage, Amazon S3, Microsoft Azure Blob Storage, Alibaba Cloud OSS Storage and Openstack Object Storage. ChartMuseum is a child project under the Helm umbrella, maintained primarily by Codefresh.

Why use Chartmuseum?

  • It' easier to distribute your charts across different deployment pipelines or repositories
  • It exposes an API for chart manipulation
  • Reduces maintenance - you can share charts or templates easily
  • Requires no effort to set it up on k8s

Installing

To deploy Chartmuseum we can use Helm obviously ;) By default the Helm chart of Chartmuseum installs with DISABLE_API set to true, we will override it with the false value for the purpose of this tutorial.

$ helm install chartmuseum --namespace default stable/chartmuseum --version 2.7.1 --set env.open.DISABLE_API=false

NAME: chartmuseum
LAST DEPLOYED: Tue May  5 10:15:07 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
** Please be patient while the chart is being deployed **


Get the ChartMuseum URL by running:


  export POD_NAME=$(kubectl get pods --namespace default -l "app=chartmuseum" -l "release=chartmuseum" -o jsonpath="{.items[0].metadata.name}")
  echo http://127.0.0.1:8080/

  kubectl port-forward $POD_NAME 8080:8080 --namespace default

To see the contents of the package and defaults please refer to the Chartmuseum chart repository on GitHub.

Charmuseum can be configured with persistence storage and ingress to be reachable from the internet. If you want a private helm repository it is best to secure the ingress with basic HTTP access authentication or used it on a private LAN.

How to use

For this tutorial I am installing the chartmuseum on my local k8s cluster and forwarding the port manually to use the repo:

$ kubectl port-forward chartmuseum-chartmuseum-7bf84f4d57-hmbts 8080:8080

Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

Handling connection for 8080

We can now add the repo to helm with:

$ helm repo add demo http://localhost:8080

"demo" has been added to your repositories

To list the repositories we run:

$ helm repo list
NAME    	URL
demo    	http://localhost:8080

Now let's upload our chart to the repo with:

$ curl --data-binary "@mychart-0.1.0.tgz" http://localhost:8080/api/charts

{"saved":true}

We need to update the repo with:

$ helm repo update

Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "demo" chart repository
Update Complete. ⎈ Happy Helming!⎈

To list the available packages on the repository:

$ helm search repo demo

NAME        	CHART VERSION	APP VERSION	DESCRIPTION
demo/mychart	0.1.0        	1.16.0     	A Helm chart for Kubernetes

And finally to install our package from the Chartmuseum repo we can run:

$ helm install mychart demo/mychart


NAME: mychart
LAST DEPLOYED: Tue May  5 10:53:44 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=mychart,app.kubernetes.io/instance=mychart" -o jsonpath="{.items[0].metadata.name}")
  echo "Visit http://127.0.0.1:8080 to use your application"

  kubectl --namespace default port-forward $POD_NAME 8080:80

Versioning

During its life, our app will have different versions. We will use helm package and curl to upload the new package to our repository. The helm search will always show the last version available on the Chartmuseum repo.

We can also visualize the various versions available on the repository adding the -l flag:

$ helm search repo demo/mychart -l

NAME        	CHART VERSION	APP VERSION	DESCRIPTION
demo/mychart	0.2.0        	1.16.0     	A Helm chart for Kubernetes
demo/mychart	0.1.0        	1.16.0     	A Helm chart for Kubernetes

The latest version of the demo/mychart package differs from the one installed on our cluster:

$ helm list

NAME       	NAMESPACE	REVISION STATUS  	CHART            	APP VERSION

mychart    	default  	1  	     deployed	mychart-0.1.0    	1.16.0

To upgrade our app now we simply run:

$ helm upgrade mychart demo/mychart


Release "mychart" has been upgraded. Happy Helming!
NAME: mychart
LAST DEPLOYED: Tue May  5 11:03:58 2020
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=mychart,app.kubernetes.io/instance=mychart" -o jsonpath="{.items[0].metadata.name}")
  echo "Visit http://127.0.0.1:8080 to use your application"

  kubectl --namespace default port-forward $POD_NAME 8080:80

The whole deploying and upgrading/downgrading subject is complex and I'm not going to describe it here, but there is a detailed tutorial on deploying, scaling and upgrading an application on Kubernetes using Helm on the Bitnami documentation pages.

Conclusions

As seen in this brief article using Helm has multiple advantages on how we handle our applications in Kubernetes. With the addition of Chartmuseum storing and versioning the packages of our application becomes a piece of cake. Also, the whole deployment of this tool is simple and easy to do that's why I recommend it to all of my clients.

Happy Helming!


References

To view or add a comment, sign in

More articles by Aleksandar Sosic

  • Introduction to the Canyan Rating project

    Canyan Rating is an open-source real-time highly scalable rating system. The rating system is a critical component in…

  • Integrating Canyan Rating with Kamailio

    The rating system is a critical component in any business, especially when real-time features are a strict requirement…

  • Wazo Platform C4 now deployable on Kubernetes

    As already mentioned We're focused on delivering a Cloud-Native telecom solution with all the bells and whistles in the…

    3 Comments
  • Wazo C4 platform overview

    Introduction Wazo Platform allows you to build your own IP communication infrastructure and deliver innovative…

    1 Comment

Insights from the community

Others also viewed

Explore topics