Skip to main content

Documentation Index

Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt

Use this file to discover all available pages before exploring further.

Helm Package Manager

Helm is the package manager for Kubernetes. It helps you define, install, and upgrade even the most complex Kubernetes application. If Kubernetes is an operating system for the cloud, Helm is its apt-get or npm — a way to install, configure, and manage applications as a single unit rather than juggling dozens of individual YAML files.

Why Helm?

Without Helm, deploying a real application to Kubernetes means managing a Deployment, a Service, a ConfigMap, a Secret, an Ingress, and possibly a dozen more resources — each in its own YAML file, each needing environment-specific values hardcoded or templated by hand. Multiply that by dev, staging, and production, and you quickly drown in copy-paste YAML. Helm solves this with Charts.

Package Management

Find, share, and use software built for Kubernetes (like apt or npm).

Templating

Use a single template for Dev, Staging, and Prod environments.

Release Management

Easy upgrades and rollbacks with revision history.

Dependency Management

Manage dependencies (e.g., your app needs Redis).

Core Concepts

Think of Helm like installing an application on your phone. The Chart is the app package in the store. The Release is the installed instance on your phone. You can install the same app multiple times (e.g., two Redis instances with different names). And a Repository is the app store where you browse available packages.
  • Chart: A bundle of templates, default values, and metadata that defines a Kubernetes application. Charts are versioned and can declare dependencies on other charts.
  • Config (values.yaml): The configuration that customizes a chart for a specific deployment. This is where you set replica counts, image tags, resource limits, and environment-specific settings.
  • Release: A running instance of a chart, combined with a specific config. Each release has a unique name and maintains a revision history for rollbacks.
  • Repository: A place where charts can be collected and shared. Artifact Hub is the public registry; teams often run private OCI registries for internal charts.

Using Helm

1. Installation

# Install Helm (Linux/macOS)
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# Add a Repository (Bitnami)
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

2. Installing a Chart

Install Redis using the Bitnami chart. One command replaces what would otherwise be creating a StatefulSet, Service, ConfigMap, Secret, and PVC by hand.
# Install a named release. "my-redis" is the release name (must be unique
# within the namespace). "bitnami/redis" is the chart reference.
helm install my-redis bitnami/redis

# List all releases in the current namespace
helm list

# Uninstall a release and delete all its Kubernetes resources.
# NOTE: PVCs created by StatefulSets are NOT deleted by default.
# You must clean those up manually to avoid orphaned storage.
helm uninstall my-redis

3. Customizing Installation (values.yaml)

You can override default settings using a values.yaml file or CLI flags. In practice, you almost always need to customize — the chart defaults are a starting point, not a production-ready configuration.
# Dump the chart's default values to a file for inspection.
# This is the first thing you should do with any new chart.
helm show values bitnami/redis > values.yaml

# Edit values.yaml to match your environment:
#   - Set replica count, resource limits, persistence size
#   - Configure authentication, TLS, network policies
#   - Override image tags for your registry

# Install with a custom values file (preferred for reproducibility)
helm install -f values.yaml my-redis bitnami/redis

# OR use --set for quick overrides (fine for testing, avoid in CI/CD
# because --set values are not version-controlled)
helm install my-redis bitnami/redis --set architecture=replication --set auth.password=secret123
Production practice: Always check in your values.yaml files to version control, one per environment. Use helm install -f values-prod.yaml in CI/CD pipelines rather than --set flags. This gives you an auditable history of every configuration change.

Creating Your Own Chart

# Scaffold a new chart. This generates a complete, working chart
# with sensible defaults that you can customize.
helm create my-chart

Structure

my-chart/
  Chart.yaml          # Metadata: name, version, dependencies, description
  values.yaml         # Default configuration values (users override these)
  charts/             # Dependency charts (downloaded via helm dependency update)
  templates/          # Go template files that generate Kubernetes manifests
    deployment.yaml   # Main application Deployment
    service.yaml      # Service to expose the Deployment
    _helpers.tpl      # Reusable template snippets (naming conventions, labels)
    NOTES.txt         # Post-install instructions shown to the user
    tests/            # Helm test hooks (optional but recommended)

Templating Example

Helm uses Go templates. The {{ .Values.x }} syntax pulls from values.yaml, {{ .Release.Name }} comes from the release metadata, and _helpers.tpl defines reusable named templates. If you have used Jinja2 or Mustache, the concepts are identical. values.yaml:
replicaCount: 3
image:
  repository: nginx
  tag: latest    # Pin to a specific tag in production, never use "latest"
templates/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
  # .Release.Name ensures unique names when the same chart is installed
  # multiple times in the same namespace (e.g., "staging-nginx", "prod-nginx")
  name: {{ .Release.Name }}-nginx
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    spec:
      containers:
        - name: nginx
          # Always quote templated image references. Without quotes,
          # YAML parsing can break on certain tag formats.
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"

Validating Before Deploying

# Render templates locally without installing (critical for debugging)
helm template my-release ./my-chart -f values-prod.yaml

# Dry-run against the cluster (validates against the API server)
helm install my-release ./my-chart --dry-run --debug

# Lint the chart for common errors
helm lint ./my-chart

Managing Releases

Helm tracks every install and upgrade as a numbered revision. This is your safety net — if an upgrade breaks something, rollback to the last known-good revision.
# Upgrade a release. Helm computes the diff between the current release
# and the new config, then applies only the changed resources.
helm upgrade my-redis bitnami/redis --set auth.password=newsecret

# View the full revision history (who deployed what and when)
helm history my-redis

# Rollback to revision 1. This creates a NEW revision (e.g., revision 3)
# that is a copy of revision 1. Helm never mutates history.
helm rollback my-redis 1

# Upgrade with --atomic: if the upgrade fails health checks within
# the timeout, Helm automatically rolls back. Highly recommended for CI/CD.
helm upgrade my-redis bitnami/redis -f values-prod.yaml --atomic --timeout 5m

Common Pitfalls

1. Using --set in CI/CD Pipelines: --set values are not version-controlled and are easy to mistype. Use -f values-prod.yaml files checked into Git instead. Reserve --set for quick local experiments.2. Not Pinning Chart Versions: helm install my-redis bitnami/redis installs the latest chart version. A chart update can change default values or templates and break your deployment. Always use --version 17.3.14 in production and CI/CD.3. Ignoring helm diff: Before running helm upgrade, install the helm-diff plugin (helm plugin install https://github.com/databus23/helm-diff) and run helm diff upgrade to see exactly what will change. Upgrading blind in production is how you accidentally delete StatefulSet PVCs or change service ports.4. Orphaned PVCs After Uninstall: helm uninstall does not delete PersistentVolumeClaims created by StatefulSets. This is by design (to prevent data loss), but it means you accumulate orphaned storage that costs money. Audit PVCs regularly.5. Massive values.yaml Files: As your chart grows, the values file becomes a wall of YAML that nobody reads. Split values by concern (e.g., values-resources.yaml, values-ingress.yaml) and merge them with multiple -f flags: helm install -f base.yaml -f prod.yaml -f secrets.yaml.

Interview Questions & Answers

Helm solves three problems: 1) Templating — one chart works across dev, staging, and prod by substituting values. 2) Package management — install complex applications (e.g., Prometheus with all its components) with a single command. 3) Release management — track revisions, upgrade atomically, and rollback when things go wrong. Without Helm, teams end up building ad-hoc templating with sed, envsubst, or Kustomize overlays, which works until you need rollback history.
Helm uses templating (Go templates with values.yaml). Charts are shareable packages. Helm tracks releases and supports rollback.Kustomize uses overlays and patches (no templates). Built into kubectl (kubectl apply -k). No release tracking or rollback.When to use which: Use Helm for third-party applications (community charts) and when you need release management. Use Kustomize for simple internal applications where overlays are sufficient. Many teams use both — Helm for installing third-party software, Kustomize for their own applications.
Never put secrets in plain-text values.yaml files committed to Git. Options:
  1. helm-secrets plugin: Encrypts values files using SOPS/AGE/PGP before committing to Git
  2. External Secrets Operator: Helm chart deploys ExternalSecret resources that sync from Vault/AWS Secrets Manager
  3. CI/CD injection: Pipeline injects secrets via --set from a secret store at deploy time
  4. Sealed Secrets: Encrypt secrets with a cluster-side key; safe to commit the encrypted form

Key Takeaways

  • Helm is the standard package manager for Kubernetes. Learn it — you will use it every day.
  • Use Repositories (Artifact Hub) to find existing software instead of writing charts from scratch.
  • Use values.yaml files per environment checked into Git for reproducibility and auditability.
  • Always use --version to pin chart versions in production and CI/CD.
  • Use helm upgrade --atomic for safe deployments with automatic rollback on failure.
  • Use helm template and helm diff to preview changes before applying them.
  • Helm and Kustomize are complementary, not competing — many production teams use both.

Interview Deep-Dive

Strong Answer:
  • Immediate recovery: run helm rollback <release> <previous-revision>. Helm stores every revision as a Kubernetes Secret (or ConfigMap, depending on the storage driver), so rollback is near-instant. I would check helm history <release> to confirm which revision was healthy and roll back to that specific one.
  • While rolling back, I would also check kubectl get pods to see if the old pods are still in a Terminating state or if new broken pods are in CrashLoopBackOff. If the rollback does not fix pod health immediately, I might need to check whether the bad values corrupted a persistent resource (like a PVC or a ConfigMap) that the rollback does not revert.
  • Guardrails: First, helm diff (a Helm plugin) should be mandatory before every upgrade — it shows exactly what Kubernetes resources will change. Second, CI/CD should run helm template and pipe the output through kubeval or kubeconform to validate the rendered manifests against the Kubernetes API schema. Third, use --atomic on helm upgrade, which automatically rolls back if the release does not reach a healthy state within the timeout. Fourth, lock down production Helm releases behind a CI/CD pipeline so developers cannot run ad-hoc upgrades.
Follow-up: What is the difference between helm upgrade --atomic and helm upgrade --wait?--wait makes the command block until all resources are in a ready state (pods running, jobs complete), but if readiness is never achieved, the release stays in a failed state and you have to manually roll back. --atomic does everything --wait does, but additionally rolls back automatically on failure. In production, I always use --atomic because a failed release sitting in limbo at 3 AM is worse than an automatic rollback.
Strong Answer:
  • Helm 3 stores each release revision as a Kubernetes Secret in the release’s namespace, with the type helm.sh/release.v1. Each Secret contains the rendered manifests, the chart metadata, and the values used for that revision. The label owner=helm identifies these Secrets.
  • If those Secrets are deleted, Helm loses all knowledge of the release. helm list shows nothing, helm upgrade fails because it cannot find a previous release to diff against, but the actual Kubernetes resources (Deployments, Services, ConfigMaps) still exist and keep running.
  • Recovery options: you can re-import the release using helm install --replace with the exact same values (risky if you do not have the values), or use community tools like helm-mapkubeapis or manually recreate the Secrets from backup. This is why etcd backups and namespace-level backup strategies (Velero) are important — they capture the Helm release Secrets along with everything else.
  • A more insidious problem is Secret size. If your chart renders a very large set of manifests, the release Secret can exceed the 1MB etcd value size limit. Helm will fail silently or with a cryptic error. I have seen this happen with charts that embed large ConfigMaps or have many subcharts. The fix is to refactor the chart to reduce rendered size, or switch Helm’s storage driver to a SQL backend.
Follow-up: How would you migrate a Helm 2 release to Helm 3?Helm 2 used Tiller (a server-side component) and stored releases as ConfigMaps in the kube-system namespace. Helm 3 removed Tiller and stores releases as Secrets in the release namespace. The official helm-2to3 plugin handles the migration: it converts ConfigMap-based release records to Secrets and moves them to the correct namespace. The actual Kubernetes resources do not change. The main risk is that Helm 3 changed how it tracks resource ownership annotations, so you need to verify that helm upgrade works correctly after migration by running a dry-run first.
Strong Answer:
  • I would use a layered values strategy. One values.yaml file contains the application defaults (image, resource requests, probe configuration). Per-environment files (values-prod.yaml, values-staging.yaml) override environment-specific settings. Per-cluster files (values-us-east-1.yaml, values-eu-west-1.yaml) override region-specific settings like replica counts, ingress hostnames, and cloud provider annotations.
  • At deploy time, Helm merges values files in order, with later files taking precedence: helm upgrade -f values.yaml -f values-prod.yaml -f values-us-east-1.yaml.
  • For the deployment orchestration across 15 clusters, I would use a GitOps tool like ArgoCD or Flux. Each cluster has an ArgoCD Application pointing to the same chart in a Git repo but with a different values overlay path. When a developer merges a change to the chart or values, ArgoCD detects the drift and syncs each cluster automatically.
  • For chart versioning, I would publish the chart to an OCI-compatible registry (like ECR or Harbor) with semantic versioning. ArgoCD applications pin to a specific chart version, and promoting a new version is a separate pull request that updates the version reference.
Follow-up: How do you handle cluster-specific secrets across 15 clusters without duplicating them in Git?Each cluster runs an External Secrets Operator instance connected to a regional secrets store (AWS Secrets Manager in that region). The Helm chart deploys ExternalSecret resources that reference secret paths like prod/us-east-1/database-url. The secret values live in the secrets store, not in Git. When a new cluster is provisioned, you create the corresponding secrets in the regional store, and ESO pulls them automatically. This way, the Helm chart is identical across clusters — only the secrets store content differs per region.

Next: Kubernetes Architecture →