A single application on Kubernetes usually needs a Deployment, a Service, an Ingress, a ConfigMap, a Secret, a HorizontalPodAutoscaler, and often more. Multiply that by staging and production, each with different replicas, domains, and resources, and copying YAML files by hand quickly becomes a source of mistakes. Helm packages those manifests into a chart with variables, installs it as a release, and keeps a history you can roll back to. Here is how to use it well.
The Main Ideas
| Term | Meaning |
|---|---|
| Chart | A folder with Chart.yaml, a values.yaml file, and a templates directory of Kubernetes manifests |
| Values | Settings such as image tag, replicas, and domain that fill in the templates |
| Template | A manifest with Go template placeholders, such as {{ .Values.image.tag }} |
| Release | One installed copy of a chart in a namespace, with its own name and revision history |
| Repository | A place to publish charts, either a classic chart repository or an OCI registry |
You can use Helm in two ways. Install charts other people maintain, such as ingress-nginx, cert-manager, or a database operator, and only write your own values. Or write a chart for your own application. Most teams do both.
Writing a Chart for Your Application
- 1Run helm create my-app to get a starting structure, then delete the templates you do not need. Treat the generated chart as a scaffold to trim.
- 2Put sensible defaults in values.yaml and document each value with a comment.
- 3Keep template logic simple. Helpers in _helpers.tpl for names and labels are useful, but deeply nested conditionals make charts hard to read.
- 4Set resource requests and limits, liveness and readiness probes, and a securityContext as defaults in the chart, so every environment gets them.
- 5Add a checksum annotation of the ConfigMap to the Deployment so Pods restart when configuration changes.
- 6Add a values.schema.json file so Helm rejects values with the wrong type or a missing required field before anything is deployed.
One Chart, Several Environments
Keep one chart and one values file per environment, such as values-staging.yaml and values-production.yaml, holding only what differs: replicas, domain, resources, and feature flags. Deploy with helm upgrade --install my-app ./chart -f values-production.yaml --set image.tag=$GIT_SHA. Use an immutable image tag such as the commit SHA so every revision points to exactly one build and a rollback restores the same image.
Upgrades and Rollbacks
- Use helm upgrade --install so the same command works for the first deploy and every later one.
- Add --atomic in Helm 3, renamed --rollback-on-failure in Helm 4, so Helm waits for Pods to become ready and rolls back automatically if they do not.
- Run helm diff upgrade from the helm-diff plugin in CI to show exactly what will change before applying it.
- Use helm history my-app to see past revisions and helm rollback my-app with a revision number to go back.
- Remember that rollback restores manifests only. Database migrations need their own backward-compatible plan.
Keep Secrets Out of Values Files
It is tempting to put database passwords in values-production.yaml. Those files end up in Git, in CI logs, and in the release data Helm stores in the cluster. Keep secrets in a secret manager such as AWS Secrets Manager, Google Secret Manager, or Vault, and sync them into Kubernetes with External Secrets Operator. Alternatively, encrypt them in Git with Sealed Secrets or SOPS. The chart then refers to the Secret by name without ever containing the value.
Test Charts in CI
- helm lint catches structural errors and missing values.
- helm template renders the manifests so they can be checked with kubeconform against the Kubernetes schema.
- Policy and security scanners such as Checkov, Trivy, or Kyverno CLI flag containers running as root, missing limits, and similar problems.
- Deploy to a short-lived cluster with kind for charts that many teams depend on.
Helm or Kustomize?
Kustomize, built into kubectl, takes plain YAML and applies patches per environment without any templating language. It suits teams that want manifests to stay readable as plain Kubernetes YAML. Helm suits applications that are installed many times with different settings, need packaging and versioning, or are shared with other teams. Both are part of the CKAD curriculum, and they also combine: GitOps tools such as Argo CD and Flux can deploy Helm charts with Kustomize patches applied on top.
A good chart is boring. Anyone on the team can read it, and the values file says everything that differs between environments.
Our CKAD training includes hands-on Helm and Kustomize labs on real clusters, from writing a first chart to upgrades, rollbacks, and per-environment configuration.
Key takeaways
- Helm packages Kubernetes manifests into charts with values, and tracks each release so it can be rolled back.
- Keep one chart and a small values file per environment, and deploy immutable image tags.
- Use helm upgrade --install with automatic rollback on failure, and review helm diff in CI before applying.
- Keep secrets in a secret manager or encrypted in Git, never in plain values files.
- Lint, render, and validate charts in CI, and use Kustomize where plain YAML with patches is enough.


