Helm
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production; see the section bibliography for the reference material consulted while preparing these pages. |
Kustomize customizes plain YAML by patching it. Helm takes the opposite route: the manifests are Go templates, parameterised by a values file, and the result of installing them is a named, versioned release that Helm can upgrade and roll back. This page is written against Helm 4.3 (Helm 3.x is still maintained but the section targets 4) and Kubernetes 1.37; see the section index for the full version baseline. Delivering charts from a Git repository is covered in GitOps and CI/CD, and chart-packaged operators appear in Custom Resources and Operators.
Concepts
-
A chart is a directory (or a
.tgzarchive) of templates and metadata describing one application. -
A release is one installation of a chart into a cluster under a name and namespace. Installing the same chart twice with different names gives two independent releases. Each
installorupgradecreates a numbered revision, and Helm stores release state as aSecretin the release namespace (typehelm.sh/release.v1). -
A repository is an HTTP server with an
index.yamlof chart archives; an OCI registry stores charts as artifacts (oci://URLs), the same registries described in Registries and Docker Hub. OCI is the recommended distribution path today. -
Values are the configuration input: the chart’s
values.yamldefaults, overridden by-f file.yamland then by--set key=value(later sources win).
What changed from Helm 3 to Helm 4
Helm 4 is a major release that keeps chart apiVersion: v2 working. Verify the authoritative list in the Helm 4
release notes before relying on any detail; the themes are:
-
Server-side apply is the default for new installs, replacing the legacy three-way merge and improving behaviour when several controllers manage the same object. Upgrades and rollbacks keep the release’s previous apply method, so releases created by Helm 3 stay on client-side apply unless
--server-sideis passed. -
Post-renderers moved to a plugin-based model, and the plugin system was reworked (including WebAssembly-based plugins).
-
Wait handling uses kstatus-based readiness (
--wait) for more reliable "is it ready" decisions. -
Renamed flags:
--atomicbecame--rollback-on-failureand--forcebecame--force-replace. -
Some long-deprecated flags and Go SDK APIs were removed, so automation written for Helm 3 should be tested with
helm templateandhelm lintbefore switching.
Charts written for Helm 3 generally install unchanged, which is why the examples below stay version-neutral where possible.
Source: Helm Docs — Using Helm and Helm Docs — Overview.
The CLI
helm install bookshelf ./charts/bookshelf -n bookshelf --create-namespace -f values-dev.yaml
helm upgrade --install bookshelf ./charts/bookshelf -n bookshelf -f values-prod.yaml --set image.tag=1.0.0
helm list -n bookshelf
helm history bookshelf -n bookshelf
helm rollback bookshelf 1 -n bookshelf
helm get values bookshelf -n bookshelf
helm uninstall bookshelf -n bookshelf
# Offline work: render, validate, inspect
helm template bookshelf ./charts/bookshelf -f values-dev.yaml
helm lint ./charts/bookshelf --strict
helm show values oci://registry.example.com/charts/bookshelf --version 0.3.0
# Preview an upgrade against the live release (helm-diff plugin)
curl -sL https://github.com/databus23.gpg | gpg --import
helm plugin install https://github.com/databus23/helm-diff/releases/latest/download/helm-diff-linux-amd64.tgz
helm diff upgrade bookshelf ./charts/bookshelf -n bookshelf -f values-prod.yaml --set image.tag=1.0.0
helm upgrade --install is idempotent and is the form used in CI, because it works for the first deployment and every
later one. helm template prints the manifests without contacting a cluster, which is the quickest way to debug a
template. helm rollback creates a new revision whose content is the old one. helm diff is not built in: the
helm-diff plugin compares the deployed release with what an upgrade would apply, which makes it a common review step
in CI. Helm 4 verifies plugin signatures, hence the key import and a release archive for the local OS and
architecture; on Helm 3, helm plugin install https://github.com/databus23/helm-diff is enough.
Source: Helm Docs — Helm Commands and helm-diff — README.
The Bookshelf chart
charts/bookshelf/
├── Chart.yaml
├── values.yaml
├── values.schema.json
├── charts/ # packaged dependencies
└── templates/
├── _helpers.tpl
├── NOTES.txt
├── deployment-catalog-api.yaml
├── service-catalog-api.yaml
├── configmap.yaml
└── tests/
└── test-connection.yaml
# Chart.yaml
apiVersion: v2
name: bookshelf
description: The Bookshelf demo application
type: application
version: 0.3.0 # chart version (SemVer)
appVersion: "1.0.0" # version of the packaged application
dependencies:
- name: postgresql
version: "16.x.x"
repository: oci://registry.example.com/charts
condition: postgresql.enabled
# values.yaml
replicaCount: 2
image:
repository: ghcr.io/example/bookshelf-catalog-api
tag: "" # defaults to .Chart.AppVersion
pullPolicy: IfNotPresent
service:
port: 80
resources:
requests:
cpu: 100m
memory: 256Mi
postgresql:
enabled: true
A values.schema.json makes bad input fail at install time rather than at runtime:
{
"$schema": "https://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["image"],
"properties": {
"replicaCount": { "type": "integer", "minimum": 1 },
"image": {
"type": "object",
"required": ["repository"],
"properties": {
"repository": { "type": "string" },
"tag": { "type": "string" }
}
}
}
}
Source: Helm Docs — Charts.
The template language
Templates use Go’s text/template plus the Sprig function library. Because the delimiters are double braces, every
template example below is shown in a listing block, where AsciiDoc leaves them alone. The constructs to know:
-
includecalls a named template from_helpers.tpland returns a string, so it can be piped (| nindent 4);tplrenders a string value as a template itself. -
rangeloops over lists and maps;withnarrows scope and skips empty values. -
toYamlconverts a value to YAML andnindent Nadds a newline and indents it, the standard way to embed a values block. -
required "message" .Values.xaborts rendering when a value is missing;defaultsupplies a fallback.
# templates/_helpers.tpl
{{- define "bookshelf.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "bookshelf.labels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end -}}
Each Deployment adds its own app.kubernetes.io/component label to both the selector and the Pod template, so the
selectors of catalog-api, reviews-api and web in the same release never overlap.
# templates/deployment-catalog-api.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "bookshelf.fullname" . }}-catalog-api
labels:
{{- include "bookshelf.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: catalog-api
template:
metadata:
labels:
{{- include "bookshelf.labels" . | nindent 8 }}
app.kubernetes.io/component: catalog-api
spec:
containers:
- name: catalog-api
image: "{{ required "image.repository is required" .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- with .Values.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
Source: Helm Docs — Chart Template Guide.
NOTES.txt is a template printed after install; use it for the URL and the next command to run. See
ReplicaSets and Deployments for the fields the Deployment
above relies on.
Dependencies, hooks and tests
-
Dependencies are declared in
Chart.yamland fetched withhelm dependency updateintocharts/;conditionandtagsswitch them on or off, and a subchart reads its own values under a key named after the subchart. -
Hooks are ordinary manifests with a
helm.sh/hookannotation (pre-install,post-upgrade,pre-deleteand so on). Apre-upgradeJob that runs database migrations is the classic case; addhelm.sh/hook-delete-policy: before-hook-creationso the Job can run again. See Jobs and CronJobs. -
Tests are Pods in
templates/tests/annotatedhelm.sh/hook: test;helm test bookshelf -n bookshelfruns them and reports pass or fail.
Artifact Hub, provenance and signing
Artifact Hub is the public index for discovering charts (and other cloud-native artifacts);
it lists metadata but does not host charts. To verify that a chart was not tampered with, Helm supports provenance
files: helm package --sign --key <key-name> --keyring <keyring-path> produces a .prov file containing the chart
hash signed with a PGP key, and helm install --verify or helm pull --verify checks it. Charts in OCI registries
can additionally be signed with registry-level tools such as Sigstore cosign. Never commit signing keys; keep them in
your CI secret store.
Publishing to an OCI registry:
helm package charts/bookshelf
helm registry login ghcr.io --username <user> --password-stdin < token-file
helm push bookshelf-0.3.0.tgz oci://ghcr.io/example/charts