Helm & Packaging
Count what one real application needs by now: a Deployment, a Service, an Ingress, a ConfigMap, a Secret, maybe a PVC and an HPA. That’s seven-plus YAML files for one service. Now run it in three environments — dev, staging, production — that differ only in replica counts, image tags, and hostnames. The naive answer is to copy all seven files three times and hand-edit the differences.
manifests/ ├── dev/ deployment.yaml service.yaml ingress.yaml ... (7 files) ├── staging/ deployment.yaml service.yaml ingress.yaml ... (7 files, 90% identical) └── prod/ deployment.yaml service.yaml ingress.yaml ... (7 files, 90% identical)This is a maintenance trap. Change the container port and you must edit it in three places without missing one. Staging and prod drift apart because someone fixed a bug in one and forgot the others. It’s the copy-paste-and-pray problem this whole book exists to kill — back at the cluster’s front door.
Helm: a package manager for Kubernetes
Section titled “Helm: a package manager for Kubernetes”Helm is the answer, and the right mental model is the one you already have from package
management in Part 1. apt installs a package — a versioned bundle plus
the metadata to install, upgrade, and remove it cleanly. Helm does the same for Kubernetes:
| Linux (apt) | Helm |
|---|---|
| package | chart |
| installed program | release |
| package repository | chart repository |
apt install | helm install |
apt upgrade | helm upgrade |
A chart is your set of manifests turned into a reusable, parameterized package. Install it and you get a release — a named, versioned instance of that chart running in the cluster. Suddenly your app is one installable, upgradable, removable unit instead of a pile of loose files.
Templating: one source, many environments
Section titled “Templating: one source, many environments”The core trick is that Helm manifests are templates. The parts that vary become placeholders filled in from a values file. You write the structure once and supply the differences as data.
A chart’s layout:
myapp/ ├── Chart.yaml # name + version of the chart itself ├── values.yaml # default values (the parameters) └── templates/ ├── deployment.yaml # templated manifests ├── service.yaml └── ingress.yamlThe template references values with {{ ... }} instead of hardcoding:
apiVersion: apps/v1kind: Deploymentmetadata: name: {{ .Release.Name }}-webspec: replicas: {{ .Values.replicaCount }} # filled from values template: spec: containers: - name: web image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"# values.yaml — the defaultsreplicaCount: 2image: repository: myapp tag: "1.4.2"Now the three environments are one chart plus three small values files — the duplication collapses to just the things that genuinely differ:
# values-prod.yaml — overrides onlyreplicaCount: 10image: { tag: "1.4.2" }# Same chart, different values per environmenthelm install web ./myapp -f values-prod.yamlhelm template web ./myapp -f values-prod.yaml # render locally to see the YAMLReleases: upgrade and roll back as one unit
Section titled “Releases: upgrade and roll back as one unit”Here’s where Helm earns its place over plain kubectl apply. Because a release is versioned, Helm
tracks the history of what was deployed and can move you forward or backward atomically — the whole app,
all its objects, as a single transaction.
helm install web ./myapp # revision 1helm upgrade web ./myapp --set image.tag=1.5.0 # revision 2helm history web # see every revision and its statushelm rollback web 1 # snap the entire release back to revision 1helm uninstall web # remove all of the app's objects at once helm history web REVISION STATUS CHART DESCRIPTION 1 superseded myapp-0.1.0 Install complete 2 deployed myapp-0.2.0 Upgrade complete │ bad deploy? ──────┘ helm rollback web 1 → back to a known-good stateCompare the manual alternative: a bad change means hand-reverting each of seven files and
kubectl apply-ing them in the right order, under pressure, hoping you didn’t miss one. helm rollback
makes “undo the deploy” a single, reliable command — which is exactly the kind of fast, safe recovery
the DORA metrics reward.
Packaging for reuse, and where this leads
Section titled “Packaging for reuse, and where this leads”Charts are also shareable. Package a chart and push it to a repository and anyone can install your app
— or you can install someone else’s. This is why you rarely deploy infrastructure like Prometheus or an
ingress controller by hand anymore; you helm install a community chart:
helm package ./myapp # → myapp-0.2.0.tgz, a portable artifacthelm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm install prom prometheus-community/kube-prometheus-stack # a whole monitoring stack, packagedWhy this makes production safer
Section titled “Why this makes production safer”The thread, one last time for this Part: what manual, error-prone step does this remove? Without Helm, multi-environment deployment is copy-pasted YAML that silently drifts, edits repeated across files where one omission ships a bug, and rollback as a frantic manual re-apply. Helm collapses the duplication into one templated chart plus small per-environment values, so dev and prod stay structurally identical and differ only where you intend. It makes a deploy a versioned release you can upgrade and — crucially — roll back with one command, turning recovery from a risky scramble into a routine. The copy-paste drift and the white-knuckle rollback both disappear. That closes Part 4: you can now declare, expose, configure, persist, scale, and package an application on Kubernetes — and you’ve seen the same idea underneath all of it, the control loop closing the gap between what you declared and what’s running.
The architect’s lens
Section titled “The architect’s lens”Step back from charts and values and judge Helm as a packaging choice:
- Why does it exist? Because one app is seven-plus manifests, and running it across dev/staging/prod the naive way means copying all of them per environment and hand-editing the few differences — a copy-paste-and-pray maintenance trap that silently drifts.
- What problem does it solve? It makes a Kubernetes app one installable, upgradable, removable unit:
templated manifests filled from a values file collapse the duplication to the bits that genuinely
differ (replica counts, image tags, hostnames), and a versioned release gives you
helm rollbackas one atomic command — the fast, safe recovery the DORA metrics reward. - What are the trade-offs? Templating is text substitution, so a placeholder can hide a typo — you
must
helm template/--dry-runto eyeball the rendered YAML before it hits production. - When should I avoid it (or pair it)? Helm is a client you run, not a control loop — it renders and applies once and doesn’t continuously watch, so nothing re-asserts desired state when the cluster drifts. For that you pair it with GitOps (Argo CD) reconciling against Git.
- What breaks if I remove it? Multi-environment deploys revert to copy-pasted YAML where one missed edit ships a bug, environments drift apart, and rollback becomes a frantic manual re-apply of seven files in the right order under pressure — instead of one versioned, atomic command.
Check your understanding
Section titled “Check your understanding”- What is the “too many YAML files” problem, and why does copying manifests per environment cause drift over time?
- Map Helm’s vocabulary onto
apt: what are a chart, a release, and a chart repository the equivalent of? - How do templates plus a values file let three environments share one source of truth? What ends up actually differing between them?
- Why is
helm rollbacksafer than manually reverting and re-applying YAML? Connect it to fast, safe recovery. - Using the book’s thread, explain what manual step Helm removes — and why Helm being a client, not a controller, leaves a gap that GitOps fills.
Show answers
- One app is seven-plus manifests, and running it across dev/staging/prod the naive way means copying all of them per environment and hand-editing the few differences. That drifts because a change (say a container port) must be edited in every copy without missing one, and a fix applied in one environment but forgotten in another silently pulls them apart.
- A chart is the package, a release is the installed program (a named, versioned instance running in the cluster), and a chart repository is the package repository — mirroring
apt’s package, installed program, and package repo. - The manifests become templates with
{{ ... }}placeholders filled from a values file, so you write the structure once and supply per-environment differences as data. Each environment is then one chart plus a small values file, and what differs is only the intended bits — replica counts, image tags, hostnames. - Because a release is versioned,
helm rollbacksnaps the entire app — all its objects — back to a known-good revision as one atomic transaction, versus hand-reverting each of seven files and re-applying in the right order under pressure. That’s the fast, low-risk recovery the DORA metrics reward. - Helm removes copy-pasted, drift-prone multi-environment YAML and white-knuckle manual rollback, collapsing it into one templated chart plus values and a one-command versioned rollback. But Helm is a client you run — it renders and applies manifests once, it doesn’t continuously watch them — so nothing re-asserts the desired state if the cluster drifts. GitOps (e.g. Argo CD) fills that gap by continuously reconciling the cluster to match Git.