Real applications are a dozen YAML files that must change together: Deployment, Service, Ingress, ConfigMap, ServiceAccount. Helm packages them as a chart, a template plus default values, and manages installs, upgrades and rollbacks as named releases. It is also how most third-party software (ingress controllers, Prometheus, databases) is distributed.
Versions in use on this date. Helm 3 (3.6 is the current series; 3.7 is expected in the coming weeks). Helm 2 and its server component Tiller reached end of life in November 2020: Helm 3 needs no server-side component and keeps release state in Secrets in the cluster. Support for storing charts in OCI registries is still experimental (HELM_EXPERIMENTAL_OCI=1).
Chart to cluster
flowchart TB
CH[Chart<br/>templates and default values] --> R
V[Your values files<br/>values-prod.yaml and --set] --> R[helm template rendering]
R --> YAML[Kubernetes manifests]
YAML --> API[Kubernetes API server]
API --> OBJ[Deployment Service Ingress ...]
H[helm install or upgrade] --> REL[(Release record<br/>Secret sh.helm.release.v1.name.vN)]
REL -->|helm history and rollback| H
REPO[Chart repository or OCI registry] -->|helm pull| CH
Using other people’s charts
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm search repo prometheus-community/kube-prometheus-stack --versions | head
helm show values prometheus-community/kube-prometheus-stack --version <pinned-version> > values-default.yaml
helm install monitoring prometheus-community/kube-prometheus-stack -n monitoring --create-namespace \
--version <pinned-version> -f values-prod.yaml --atomic --timeout 10m
helm list -A
helm status monitoring -n monitoring
helm get values monitoring -n monitoring # what you overrode
helm get manifest monitoring -n monitoring | less # what is actually deployed
Habits: always pin --version, keep your overrides in a values file in Git (not scattered --set flags), and read helm show values and the chart README before installing. --atomic rolls back automatically if the install or upgrade fails, and --wait waits for resources to be ready.
Upgrade and roll back
helm diff upgrade monitoring prometheus-community/kube-prometheus-stack -n monitoring --version <next-version> -f values-prod.yaml # plugin: helm plugin install https://github.com/databus23/helm-diff
helm upgrade monitoring prometheus-community/kube-prometheus-stack -n monitoring --version <next-version> -f values-prod.yaml --atomic
helm history monitoring -n monitoring
helm rollback monitoring 3 -n monitoring
helm uninstall monitoring -n monitoring
The diff step shows what will change before you apply it. Note that Helm does not upgrade CustomResourceDefinitions placed in a chart’s crds/ directory; large charts document manual CRD steps in their upgrade notes.
A chart of your own
helm create shop-web
tree shop-web
# shop-web/Chart.yaml values.yaml templates/{deployment,service,ingress,_helpers.tpl,NOTES.txt}
values.yaml:
replicaCount: 2
image:
repository: registry.example.com/shop/web
tag: "1.4.2"
service: { port: 80 }
ingress:
enabled: true
host: shop.example.com
resources:
requests: { cpu: 100m, memory: 128Mi }
A template fragment, templates/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "shop-web.fullname" . }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels: {{- include "shop-web.selectorLabels" . | nindent 6 }}
template:
metadata:
labels: {{- include "shop-web.selectorLabels" . | nindent 8 }}
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
spec:
containers:
- name: web
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
resources: {{- toYaml .Values.resources | nindent 12 }}
The checksum/config annotation changes whenever the ConfigMap changes, so pods restart on configuration updates.
Test before releasing:
helm lint shop-web
helm template shop-web ./shop-web -f values-prod.yaml | kubectl apply --dry-run=server -f -
helm upgrade --install shop-web ./shop-web -n shop --create-namespace -f values-prod.yaml --atomic
Package and share with helm package shop-web and a repository or registry; version the chart (version) separately from the application (appVersion).
Practices
- Keep one release per application per environment, with values files per environment (
values-staging.yaml,values-prod.yaml). - Don’t put secrets in values files committed to Git; use Sealed Secrets, SOPS (
helm-secrets) or an external secrets operator. - Review rendered output (
helm template) in pull requests, or use a GitOps tool such as Argo CD or Flux to apply charts from Git. - Avoid editing live objects with
kubectl editon Helm-managed resources; the next upgrade overwrites the change. - Release state lives in Secrets; large releases can hit size limits, so split huge charts.
Troubleshooting
UPGRADE FAILED: another operation is in progress: a previous run was interrupted; checkhelm history, andhelm rollbackto the last good revision.rendered manifests contain a resource that already exists: the object was created outside Helm; adopt it by adding Helm labels and annotations, or delete and re-install.no matches for kind ... in version ...: the chart uses an API that your cluster no longer serves (see the 1.22 removals post); upgrade the chart.- Wrong values applied:
helm get values --allshows merged values; later-ffiles and--setwin.