All articles

Deploying Applications to Kubernetes With Helm: A Practical Guide

What Helm charts are, how values and templates work, how to structure a chart for several environments, upgrade and rollback safely, keep secrets out of Git, test charts in CI, and decide between Helm and Kustomize.

DevOps|Published |9 min read
Aerial view of a busy container port with cranes and stacked shipping containers

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

TermMeaning
ChartA folder with Chart.yaml, a values.yaml file, and a templates directory of Kubernetes manifests
ValuesSettings such as image tag, replicas, and domain that fill in the templates
TemplateA manifest with Go template placeholders, such as {{ .Values.image.tag }}
ReleaseOne installed copy of a chart in a namespace, with its own name and revision history
RepositoryA 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

  1. 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.
  2. 2Put sensible defaults in values.yaml and document each value with a comment.
  3. 3Keep template logic simple. Helpers in _helpers.tpl for names and labels are useful, but deeply nested conditionals make charts hard to read.
  4. 4Set resource requests and limits, liveness and readiness probes, and a securityContext as defaults in the chart, so every environment gets them.
  5. 5Add a checksum annotation of the ConfigMap to the Deployment so Pods restart when configuration changes.
  6. 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.

Related articles

More articles on software development, AI, cloud, and infrastructure.

Hands sorting printed tax forms and receipts next to a calculator
AI Development|

Automating Document Data Entry With AI: Invoices, Receipts, and Forms

How AI reads invoices, receipts, ID cards, and forms and turns them into structured data, how OCR and large language models fit together, why validation and human review still matter, how to measure accuracy, and what to watch for with personal data.

Person using a smartphone next to a laptop on a desk
Mobile Development|

Flutter State Management: Provider, Riverpod, or Bloc?

What state management solves in Flutter, when setState is enough, how Provider, Riverpod, and Bloc differ in practice, how to pick one for your team, and the structure that keeps a Flutter app maintainable whichever library you choose.

Looking for a software development partner?

Tell us about your project, what you need to build, and the challenges you are facing. We can discuss the technical approach, scope, timeline, and estimated cost.

Start a conversation