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.yaml
includes Charts informations such as its name, description and version.
You can find a description of all fields available hereValues.yaml
contains all default values for the Chart, this values are also use for documentation.
We will see later on, how values are very useful.templates
directory contains all YAML manifests needed to deploy the application_helpers.tpl
is the default file to store helpers that can be accessed by name elsewhere.tests
directory is optional and contains the tests files.charts
directory will contains all dependences. As there is no dependency in this example, it is empty..helmignore
allows 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:
Templates
are 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.yaml
file.
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 keywordrange
is used- Loops change the
current context
so 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 Chart
As we saw previously, you can override the values with
-f
options.
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: