Stackbook Logo
← Back to Tools

Helm Charts Guide for Kubernetes

Package, template and release Kubernetes applications with Helm: chart structure, values, upgrades, rollbacks and common pitfalls.

4 min read

What it is and when to use it

Helm is the package manager for Kubernetes. A chart bundles templated manifests, default configuration and metadata into a versioned archive. Installing a chart produces a release, which Helm tracks so it can upgrade or roll back the whole application as one unit.

Use Helm when you deploy the same application to several environments with different settings, when you consume third-party software such as ingress controllers or databases, or when you want versioned, rollback-able releases. For very simple needs, plain manifests or Kustomize may be enough.

Quick start

Add a repository, inspect a chart, and install it.

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm search repo nginx
helm show values bitnami/nginx > values-default.yaml
helm install web bitnami/nginx --namespace demo --create-namespace \
  --set replicaCount=2
helm list -n demo
helm status web -n demo

Create your own chart.

helm create myapp
helm lint myapp
helm template myapp ./myapp -f values-prod.yaml
helm install myapp ./myapp -n prod -f values-prod.yaml

Chart structure

myapp/
  Chart.yaml
  values.yaml
  templates/
    deployment.yaml
    service.yaml
    _helpers.tpl
    NOTES.txt
  charts/

Chart.yaml holds metadata. Note the difference between the chart version and the application version.

apiVersion: v2
name: myapp
description: Example web service
type: application
version: 0.3.0
appVersion: "1.4.2"

Core concepts

Values are the configuration inputs. Defaults live in values.yaml, and each environment overrides them with its own file.

replicaCount: 2
image:
  repository: ghcr.io/example/myapp
  tag: "1.4.2"
service:
  port: 80
resources:
  limits:
    memory: 256Mi

Templates use Go templating with the Sprig function library. This deployment excerpt shows the usual patterns.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "myapp.fullname" . }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ include "myapp.name" . }}
  template:
    metadata:
      labels:
        app: {{ include "myapp.name" . }}
    spec:
      containers:
        - name: app
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          resources:
            {{- toYaml .Values.resources | nindent 12 }}

Releases and revisions. Each install or upgrade creates a numbered revision stored as a Secret in the cluster.

helm upgrade --install myapp ./myapp -n prod -f values-prod.yaml --atomic --timeout 5m
helm history myapp -n prod
helm rollback myapp 2 -n prod
helm uninstall myapp -n prod

Dependencies are declared in Chart.yaml under dependencies, then fetched with helm dependency update. This lets an application chart pull in a database subchart, configurable under its own values key.

Hooks run Jobs at lifecycle points such as pre-install or post-upgrade, commonly for database migrations.

Packaging and OCI. Charts can be pushed to any OCI registry.

helm package myapp
helm push myapp-0.3.0.tgz oci://ghcr.io/example/charts
helm install myapp oci://ghcr.io/example/charts/myapp --version 0.3.0

Pitfalls

  • Always render before applying. Run helm template or helm upgrade with --dry-run to see the final YAML.
  • Indentation mistakes in templates are the most common bug. Use nindent with toYaml and the whitespace trimming markers.
  • Use --atomic or --wait so failed upgrades roll back automatically rather than leaving a half-deployed release.
  • Pin chart versions with --version. Floating to latest in production leads to surprise changes.
  • Do not put secrets in values files committed to Git. Use sealed secrets, External Secrets or a plugin such as helm-secrets.
  • Custom resource definitions in the crds directory are installed once and never upgraded or deleted by Helm, so manage CRD upgrades separately.
  • Changing a Deployment selector between versions fails, because selectors are immutable.
  • Avoid heavy logic in templates. If a chart needs many conditionals, consider splitting it.

How it fits an architecture

Helm sits between your build and your cluster. CI builds an image and publishes it along with a chart version; a deployment tool then installs the chart with environment-specific values. In GitOps setups, Argo CD or Flux renders Helm charts directly from Git or an OCI registry, so humans rarely run helm install by hand. Terraform can bootstrap the cluster and also install foundational charts such as an ingress controller using the Helm provider.

Key takeaways

  • A chart is a versioned template bundle; a release is one installed instance of it.
  • Keep values.yaml as safe defaults and override per environment with separate files.
  • Use helm lint, template and dry-run before every upgrade.
  • Prefer upgrade with install, atomic and timeout flags for dependable pipelines.
  • Pin versions, keep secrets out of values files, and handle CRDs deliberately.