Helm 101
What is Helm ?
From Helm repository
Helm is a tool for managing Charts. Charts are packages of pre-configured Kubernetes resources.
Helm allows to deploy and manage Kubernetes application as a unit of deployment which means you can manage your deployment like it is “one object”.
This unit of deployment is call a Chart and bundles one or more Kubernetes YAML manifests that define all the resources required by the application.
Helm also manage the upgrade and the rollbacks of your application.
You can think of it as a package manager for Kubernetes, like apt or homebrew.
To install helm
Helm chart
When you deploy an application on Kubernetes, you generally need to create different resources.
Let’s consider a simple todo API, the minimum you need is:
- A deployment to manage your pods
- A service to ensure load-balancing between our pod
- An ingress to expose HTTP(S) endpoint from outside the cluster to the service
All those resources are defined in separate YAML manifests, and we need to manage them all to ensure our todo API run properly.
As we see previously, the Helm Chart bundles all the YAML files and treat then as a unit of deployment.
Instead of having to think about deploying all manifests we need, we can use simply one command.
> helm install ReleaseName MyChart
Helm really shine because it’s not just about deploy application but manage it.
When you install a Chart, it is versioned (everything is stored in Kubernetes secrets).
That allows us to quickly rollback to a previous version or upgrade our deployment.
It possible to list all helm charts installed on the cluster and see the chart version and the current revision as well.
> helm list -A
The -A option allows to see on all namespaces and the -n allows to specify a namespace (like kubectl binary).
Helm chart structure
Let’s create a Chart for our simple todo API.
To boostrap a new Chart, we simple need to run the helm create command.
> helm create todo
It will create a directory filled with everything needed.
The create command generate a sample chart that deploy nginx to get started easily.
todo
├── .helmignore
├── Chart.yaml
├── charts
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml
Chart.yamlincludes Charts informations such as its name, description and version.
You can find a description of all fields available hereValues.yamlcontains all default values for the Chart, this values are also use for documentation.
We will see later on, how values are very useful.templatesdirectory contains all YAML manifests needed to deploy the application_helpers.tplis the default file to store helpers that can be accessed by name elsewhere.testsdirectory is optional and contains the tests files.chartsdirectory will contains all dependences. As there is no dependency in this example, it is empty..helmignoreallows to exclude files/directory when the chart ispackaged.
Which means the excluded resources will not be included in the chart.
Let’s do some cleaning by deleting the charts folder, the content of the templates directory and the content of the values.yaml.
Helm Template
Let’s consider we have the following deployment manifest and two others for the service and ingress.
apiVersion: apps/v1
kind: Deployment
metadata:
name: todo-deployment
labels:
app: todo
spec:
replicas: 3
selector:
matchLabels:
app: todo
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: todo
spec:
containers:
- image: example/todo:1.0
name: todo
ports:
- containerPort: 8080
As we previously see, to be able to install our application with helm we just need to copy our manifest in the templates directory and then use the helm install command.
But now, let’s imagine we want to deploy another version of our todo, we will have to duplicate our chart and change at least the name and the image’s tag.
The main problem with that is we have to maintain two charts which do the same things with only some different values.
This could lead to issue or oversight in the charts maintenance.
Helm tackles this by providing a templating system and replacing all mustache sections with provided values present in the values.yaml file.
The templating is really more powerfull than just replace the values when rendering, it also allows to add logic in charts, such as control flow, loop, etc..
This is how our above deployment could look like with templating.
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-deployment
labels:
app: {{ .Release.Name }}
spec:
replicas: {{ .Values.replicas }}
selector:
matchLabels:
app: {{ .Release.Name }}
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: {{ .Release.Name }}
spec:
containers:
- image: {{ .Values.image.name }}:{{ .Values.image.tag }}
name: {{ .Release.Name }}
ports:
- containerPort: {{ .Values.containerPort }}
# values.yaml
# releaseName: todo
replicas: 3
containerPort: 8080
image:
name: "example/todo"
tag: 1.0
Let’s review the template:
Templatesare YAML manifest with mustache syntax{{ }}defining dynamic sections that should be replaced.- Helm provides various variables that will be populated at install time (ex
{{ .Release.Name }}). - You can provide values at install time, if no values are provided, helm will use the default one defined in
values.yamlfile.
You can provide values either with a value file using -f option.
> helm install ReleaseName MyChart -f values-override.yaml
or with the --set option
> helm install ReleaseName MyChart --set MyValue=2
# example with tag
> helm install todo todoChart --set image.tag=1.1
Advance Helm Template
Now, let’s see how could look like our ingress template.
# templates/ingress.yaml
{{- if .Values.ingress.enabled }} # Condition on enabled value
{{- $name := .Release.Name }} # variable declaration
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
{{- toYaml .Values.ingress.annotations | nindent 4 }} # Using helpers
name: "{{ $name }}-ingress" # Using a variable
spec:
ingressClassName: nginx
rules:
{{- range .Values.ingress.hosts }} # loop on hosts array in values
- host: {{ .host | quote }} # current host, context change in loop to be set on the current object of iteration
http:
paths:
{{- range .paths }} # loop on paths array in hosts section
- backend:
service:
name: "{{ $name }}-svc"
port:
number: {{ $.Values.service.port }} # $ allows to use root context
path: {{ .path }} # Context is on current path object
pathType: Prefix
{{- end }}
{{- end }}
{{- end }}
The ingress demonstrates a number of features of Helm templates:
Condition: the condition is defined with{{- if CONDITION }}and scoped all inside until the{{- end }}Variable: We can define variable inside template with{{- $varName := varValue }}Loop: the loop syntax is the same as condition except the keywordrangeis used- Loops change the
current contextso the.references the current object of the iteration $refers to the root context
The values.yaml file:
# values.yaml
# releaseName: todo
replicas: 3
containerPort: 8080
image:
name: "example/todo"
tag: 1.0
service:
port: 80
ingress:
enabled: true
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
hosts:
- host: "example.com"
paths:
- path: /
- host: "example2.com"
paths:
- path: /
Package / Install / Upgrade / Uninstall
Package
When helm chart is ready we can package and install it.
Package a chart is basically bundle everything into a tgz named by combining its name and version.
# inside the chart folder
> helm package .
Successfully packaged chart and saved it to: /YOUR/PATH/todo-0.1.0.tgz
Install
A chart can be stored locally or hosted in remote chart repository.
So their is mainly 3 ways to install a chart
- From source
> helm install ReleaseName . - From tgz
> helm install ReleaseName chart.tgz - From remote repository
# add the repository > helm repo add NAME URL > helm install ReleaseName ChartAs we saw previously, you can override the values with
-foptions.
Upgrade
To upgrade the installed chart, we need to proceed like the installation but using the helm upgrade command instead.
The revision of the release will be incremented by 1.
> helm upgrade ReleaseName chart.tgz
When upgrading, we can either provide new values with -f option or reuse the one used previously with --reuse-values option.
> helm upgrade ReleaseName chart.tgz --reuse-values
To have information on a release, we can use the helm show command with one of its subcommands.
> helm show -h
This command consists of multiple subcommands to display information about a chart
Usage:
helm show [command]
Aliases:
show, inspect
Available Commands:
all show all information of the chart
chart show the chart's definition
crds show the chart's CRDs
readme show the chart's README
values show the chart's values
We can have information on the differents revisions with the helm history command.
> helm history ReleaseName
Finally, to rollback to a previous revision, we will use the helm rollback command.
> helm rollback ReleaseName Revision
Uninstall
To remove all resources associated with the installed chart, we need the helm uninstall command.
> helm uninstall ReleaseName
Debug Chart
To validate and/or debug a chart we can combined the --dry-run and --debug options on the helm install command.
> helm install ReleaseName chart.tgz --dry-run --debug
The chart will not be installed, but it will be rendered and validated.
In case of error, a stack trace will be provided to help identify and fix the issue.
It’s also possible to just render a chart or a file with the helm render command.
# inside the chart folder
> helm template .
# A specific file
> helm template . -s templates/someFile.yaml
To infinity and beyond …
To have deeper understanding, you can recreate the default chart and analyse all files. Also some readings: