Helm Introduction
1. What does helm install do behind the scenes?
- Step 1: Chart resolution
- Helm looks for the chart (
<chart>) either locally or from a remote chart repository (likehttps://charts.bitnami.com/bitnami). - It loads the chart into memory, including:
Chart.yaml: metadatavalues.yaml: default configuration valuestemplates/: YAML templates with Go templating- Any other custom files like
NOTES.txt
- Helm parses the
Chart.yaml(chart metadata) andvalues.yaml(default values) using a YAML parser. If you pass a custom values file (-f my-values.yaml) or--setflags, those are also parsed.
The first thing Helm does when you do a helm install is to load the chart and its dependencies. If it is a local chart, it will simply load it from your local machine. If it is a chart living on a repository, it will pull that chart and it will load it.
- Step 2: Merge Values
- Helm merges configuration values:
values.yaml- Any
--values(-f) file provided - Any
--setCLI overrides
- The result is a single values map used to render templates.
- Step 3: Template Rendering
- Helm renders the Go templates inside
templates/directory using the merged values. - This results in standard Kubernetes manifests (YAML) — like
Deployments,Services,Ingress,ConfigMaps, etc. - The produces final YAML documents are in ** plain text**. These rendered YAMLs are still just strings at this point.
- Step 4: Install Release to Kubernetes
-
Before sending to Kubernetes, Helm parses the rendered YAMLs to:
- Validate them structurally (to some degree)
- Convert them to Kubernetes API-compatible JSON objects (Kubernetes API works with JSON under the hood)
- Invalid YAMLs here will raise errors (e.g. bad indentation, missing colons).
- Helm needs to convert YAML to internal objects to check for things like hooks, CRDs, kinds, etc.
- Kubernetes itself also validates these later, but Helm catches obvious issues first.
-
Helm then connects to the Kubernetes cluster (via
~/.kube/configorcontext). -
It sends the rendered manifests to the Kubernetes API server.
-
The Kubernetes API server validates and stores the manifests in etcd.
-
Resources are then created by Kubernetes controllers (e.g.,
DeploymentcreatesPods).
- Step 5: Create Release Record (in Cluster)
- Helm stores a release object in the cluster using
secrets/configmapsin the release namespace. (in older versions, 2 and below, it would store them in the namespacekube-system). - The release record includes:
- Rendered manifests
- Chart metadata
- Values used
- Version info
- Step 6: Run Hooks (if any exists)
- Helm checks for lifecycle hooks defined in templates (like pre-install, post-install).
- These jobs/pods are created and monitored.
- Step 7: Show Output
If successful, Helm outputs the status. Release name, namespace, resources created, and any messages from NOTES.txt (templated and displayed).
2. A successful installation/upgrade
helm considers an installation successful as soon as the manifest is received by the kubernetes API server. It doesn't wait for the pods to be up and running.
If you want that to happen, you can use the --wait flag. With it, helm will wait for the services and deployments to be created, and for the pods to be up and running. Only then the installation is considered successful.
By default, helm waits about 5 minutes (300 seconds), and if the installation doesn't complete by that time, the installation is marked as failure. If you want to override the default timeout, you can use the --timeout flag, followed by the time. Examples of valid time values: 5m, 10s, 5m10s (without quotes!).
3. A failed installation
By default, upon a failure, created resources remain created (i.e. secrets), and the pod is endlessly and desperately trying to live.
In such case, you have a few options:
- Option 1: Do nothing
Bad idea. You are leaving a dirty environment, and a pod that's endlessly and desperately trying to live takes up resources, which costs money.
- Option 2: Go back to a previous successful release
If you want to go back to a previous successful release, and keep your deployment as clean as possible, use the --atomic flag. If --atomic is set, the upgrade process rolls back changes made in case of failed upgrade. The --wait flag will be set automatically if --atomic is used.
What this will do:
- remove secrets
- kill the pod (euthanize)
A full command would look like:
helm upgrade RELEASE --values values.yaml --wait --timeout 7m --atomic
- Option 3: cleanup on fail
Cleanup on fail cleans up (i.e.) deletes any secrets and objects created due to the failed upgrade. It is different than go back to a previous release in 2 ways:
- It doesn't create a new helm-history item (stored as a secret)
- It doesn't kill the pod trying to live.
4. A Forceful Upgrade
What does it mean to use --force with upgrade?
we do a helm upgrade, kubernetes receives a request to modify the existing objects. It will restart only the pods whose values have changed. It will NOT restart all the pods all the time. It will only restart the pods if there are any values that have changed for those pods. But if we have a requirement where you want to forcefully restart all pods, you can use the --force option. Internally, helm will delete the current deployment. Instead of modifying the deployment, it will delete the deployment, and it will recreate the deployment. As a result, Kube will delete the old pods and create new ones. So there will be some downtime when you use --force option. This is a major risk of using --forceflag.
5. Creating a Chart
When you run helm create CHART_NAME, a folder will be created with the following structure:
- Chart.yaml
- values.yaml
- templates/
- charts/
- A. Chart.yaml
• Description
The Chart.yaml for helm is much like what the package.json is for npm.
The Chart.yaml is a required metadata file for every Helm chart. It serves as the manifest that defines the chart itself.
• Purpose of Chart.yaml
It contains key metadata about your chart so that Helm and other tools know:
- What the chart is
- What version it is
- What it depends on
- What Kubernetes resources it describes
• Common fields in Chart.yaml
apiVersion: v2
name: my-app
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: "1.16.0"
| Field | Purpose |
|---|---|
| apiVersion | (required) Chart API version (v2 for Helm 3). |
| name | (required) Name of the chart. |
| version | (required) Version of the chart itself. Helm uses this for upgrades and rollbacks. |
| description | Short human-readable summary. |
| type | application (default) or library. |
| appVersion | Version of the actual app being deployed (informational). i.e, MongoDB 8.0 |
• Why it matters
- Helm installs and upgrades charts based on
version. dependenciescan be listed here, allowing Helm to pull in subcharts automatically.- Tools like
helm repoandhelm packageread this file to index and distribute your chart.
• More optional keys
- You can specify an
icon. - You can specify
keywords. - You can specify
home, which is the home url of your project. maintainers: list of people maintaining this chart.
-B. helpers
_helpers.tpl
It starts with an underscore (_) so that it would always come on top.
The tpl stands for template.
The _helpers.tpl contains methods that can be used in a .yaml file. If you open it you can see a bunch of functions defined.
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "hello.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "hello.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
6. Templating Syntax & tricks
- A. if statement
{{- if .Values.ingress.enabled}}
- B. include
include is a way to invoke a helper function, defined in one of your .tpl files.
You can pass all parameters to it like so: .
{{ include SOME.FUNC.NAME}}
7. helm package
To package a chart, go to the command line, and type:
helm package path/to/chart-root
The output of this command is a file named: CHART_NAME-0.1.0.tgz.