Chapter 61 -- Helm and packaging Kubernetes applications
In one sentence
Helm is a package manager for Kubernetes -- it turns a directory of
templated YAML into a versioned, install/upgrade/rollback-able "chart," for
the same reason apt exists instead of everyone compiling and copying
binaries by hand.
Why this matters
A real application is rarely one Deployment. It's a Deployment, a Service, a ConfigMap, maybe a Secret, an Ingress, a HorizontalPodAutoscaler -- 6 to 15 YAML files that all need to agree with each other (same labels, same names, same namespace) and that change slightly between environments (dev uses 1 replica and no autoscaling, prod uses 5 and does). Copy-pasting these YAML files between environments and hand-editing the differences is exactly the class of manual, error-prone, "someone forgot to update the image tag in staging" work that Helm exists to eliminate.
For a manager: Helm charts are also how most third-party software gets
installed onto Kubernetes today (Prometheus, cert-manager, ingress
controllers, databases) -- "just helm install it" is the standard onboarding
instruction across the ecosystem, so basic Helm literacy is close to a
baseline expectation for anyone operating a cluster, not a specialist skill.
How it actually works
A CHART is a directory:
mychart/
Chart.yaml -- name, version, description
values.yaml -- default configuration values
templates/
deployment.yaml -- Go-template YAML, referencing .Values.*
service.yaml
configmap.yaml
charts/ -- bundled dependencies (sub-charts)
templates/deployment.yaml might contain:
replicas: {{ .Values.replicaCount }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
values.yaml (the defaults):
replicaCount: 1
image:
repository: myapp
tag: latest
A production override, values-prod.yaml:
replicaCount: 5
image:
tag: v2.4.1
The commands that matter day to day:
helm install myapp ./mychart -f values-prod.yaml # first install
helm upgrade myapp ./mychart -f values-prod.yaml # apply changes
helm rollback myapp 3 # back to revision 3
helm history myapp # see revisions
helm template ./mychart -f values-prod.yaml # render YAML,
# don't apply --
# use this to review
# exactly what
# would be sent to
# the cluster
helm uninstall myapp
Every helm upgrade is a new numbered revision, tracked by Helm as a
Secret in the cluster -- which is what makes helm rollback possible: it
isn't magic, it's "re-apply the exact rendered YAML from revision N."
Real-world example
The Kubernetes package ecosystem's default answer to "how do I run
Prometheus" or "how do I run an nginx ingress controller" is, almost
universally, a Helm chart from the project's own repository or from
Artifact Hub (the successor to the old central "stable" Helm chart
repository). This is not incidental: Helm charts became the de facto
distribution format precisely because hand-writing 10+ YAML files for
Prometheus's Deployment, Services, RBAC rules, ConfigMaps, and
PersistentVolumeClaims -- correctly, for your specific cluster's storage
class and resource limits -- is enough work that essentially nobody wants
to do it themselves. A commonly repeated cautionary lesson in platform
engineering, though, is helm install-ing a chart without reading
values.yaml first: charts often ship reasonable defaults for a generic
cluster, but a default like persistence.enabled: false on a database
chart or a resources: {} with no limits can silently mean "this loses
its data on every restart" or "this can consume unbounded memory on your
node" -- and because Helm makes installation so effortless, teams
routinely encounter these gaps only once the workload is already running
in production. The practical rule that has emerged across SRE teams is:
helm template and read the rendered output before ever running helm install on anything you didn't author yourself.
Try it yourself
# Requires helm installed and a cluster (minikube/kind is fine).
helm create demochart
ls demochart/templates/
# Render without installing -- read this output before ever installing
# a chart you didn't write
helm template demochart
helm install demo ./demochart
helm list
helm upgrade demo ./demochart --set replicaCount=3
helm history demo
helm rollback demo 1
helm uninstall demo
Common mistakes
- Running
helm installon an unfamiliar third-party chart without first runninghelm templateto see exactly what it creates -- including RBAC permissions and resource limits (or their absence). - Editing a running application's Kubernetes objects directly with
kubectl editafter it was installed via Helm -- the nexthelm upgradesilently overwrites the manual change, because Helm has no idea it happened. - Treating
values.yamldefaults as production-appropriate without reading them, especiallyreplicaCount,resources, andpersistencesettings. - Not pinning chart versions (
helm install myapp repo/chartwithout--version), so the same install command produces a different chart version, with different defaults, weeks later.
Check yourself
- What does
helm rollback myapp 3actually do, mechanically -- what is Helm re-applying? - Why does hand-editing a Helm-managed Kubernetes object with
kubectl editcause problems later, even if the edit itself is correct? - Why is
helm templaterecommended beforehelm installfor a chart you didn't write yourself?
Further reading
- Helm official documentation, "Helm Charts" and "Using Helm" (helm.sh/docs)
- Artifact Hub (artifacthub.io) -- the community index of published Helm charts
- CNCF, "Helm" project page and graduation announcement (Helm graduated as a CNCF project in 2020)