Kubernetes Lesson 54 – Helm Introduction | Dataplexa
Advanced Workloads & Operations · Lesson 54

Helm Introduction

As your cluster grows, managing dozens of related Kubernetes manifests by hand becomes brittle. Helm is the Kubernetes package manager — it bundles related manifests into a versioned chart, parameterises them with a values file, and tracks every release so you can upgrade, rollback, and audit history atomically. This lesson covers the fundamentals: finding charts, installing them, customising with values, and managing the release lifecycle.

What Problem Does Helm Solve?

Installing NGINX Ingress Controller from scratch requires: a Namespace, ServiceAccount, two ClusterRoles, two ClusterRoleBindings, a ConfigMap, a Deployment, a Service, a ValidatingWebhookConfiguration, and an IngressClass. That is ten manifests, carefully ordered, with values that must be consistent across all of them. Helm packages all of this as a single installable unit — one command, one version, one rollback.

Without Helm

10 separate kubectl apply commands. Manual version tracking. Rollback means reverting each manifest individually. "What's deployed?" requires diffing YAML files.

With Helm

helm install ingress-nginx ingress-nginx/ingress-nginx. One command installs everything. helm rollback reverts all 10 resources atomically.

Core Concepts

Term What it means
Chart A packaged collection of Kubernetes manifests plus a values.yaml. Versioned and distributable. Like an apt package for Kubernetes.
Release An installed instance of a chart. One chart can produce many releases — mysql-payments and mysql-analytics from the same chart, different configurations.
Repository An HTTP server hosting chart packages and an index. Add once with helm repo add, then install any chart from it by name.
Values Configuration that customises the chart at install time — image tags, replica counts, resource limits. Supplied via -f values.yaml or --set key=value.
Revision Every install or upgrade increments a counter. Helm stores rendered manifests for each revision, enabling rollback to any previous state.

Finding and Installing Charts

The scenario: Your cluster needs NGINX Ingress Controller. Rather than hunting down upstream manifests, you find the official Helm chart, inspect its default values, and install it with settings tuned for your environment.

# Add repositories
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update                     # Refresh all repo indexes

# Search for charts
helm search repo ingress-nginx       # Search added repos
helm search hub nginx                # Search Artifact Hub (public registry)

# Inspect the chart before installing
helm show chart ingress-nginx/ingress-nginx    # Metadata: description, version, dependencies
helm show values ingress-nginx/ingress-nginx   # All configurable values with comments
# Tip: pipe to a file, edit, then install with -f:
helm show values ingress-nginx/ingress-nginx > my-values.yaml

# Install
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace \
  --version 4.9.1 \
  --set controller.replicaCount=2 \
  --set controller.service.type=LoadBalancer \
  --wait \                           # Block until all Pods are Ready
  --timeout 5m
$ helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace \
  --version 4.9.1 --set controller.replicaCount=2 --wait
NAME: ingress-nginx
LAST DEPLOYED: Mon Mar 10 11:04:22 2025
NAMESPACE: ingress-nginx
STATUS: deployed
REVISION: 1

$ helm list -n ingress-nginx
NAME           NAMESPACE      REVISION  UPDATED              STATUS    CHART                  APP VERSION
ingress-nginx  ingress-nginx  1         2025-03-10 11:04:22  deployed  ingress-nginx-4.9.1    1.10.0

# Helm stores release state as a Secret in the namespace
$ kubectl get secrets -n ingress-nginx | grep helm
sh.helm.release.v1.ingress-nginx.v1    helm.sh/release.v1    1    5m
# This Secret contains the rendered manifests -- used for diffs and rollbacks

What just happened?

Helm rendered and applied all 10 resources in one command — Under the hood, Helm merged your --set overrides with the chart's default values, ran the Go templates to produce Kubernetes manifests, and applied them. The --wait flag blocked until every Deployment's Pods were Ready — not just submitted to the API server.

Release state lives in a namespace Secret — Helm 3 stores each revision's rendered manifests as a compressed Secret (type helm.sh/release.v1) in the release namespace. This is how helm rollback works without needing Git access — it reads the stored manifests from the target revision and re-applies them.

Customising with Values Files

For anything beyond a quick test, supply values in a YAML file rather than chaining --set flags. Values files are readable, committable to Git, and reusable across environments.

# ingress-nginx-values.yaml
controller:
  replicaCount: 2

  service:
    type: LoadBalancer
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-type: nlb
      service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing

  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 256Mi

  metrics:
    enabled: true
    serviceMonitor:
      enabled: true              # Create a ServiceMonitor for Prometheus

  config:
    use-forwarded-headers: "true"
    ssl-protocols: "TLSv1.2 TLSv1.3"

podDisruptionBudget:
  enabled: true
  minAvailable: 1
# This is a values file -- applied at install/upgrade time with -f
# No direct kubectl output, but after helm install -f ingress-nginx-values.yaml:

$ helm get values ingress-nginx -n ingress-nginx
controller:
  config:
    ssl-protocols: TLSv1.2 TLSv1.3
    use-forwarded-headers: "true"
  metrics:
    enabled: true
    serviceMonitor:
      enabled: true
  replicaCount: 2
  resources:
    limits:
      cpu: 500m
      memory: 256Mi
    requests:
      cpu: 100m
      memory: 128Mi
  service:
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
      service.beta.kubernetes.io/aws-load-balancer-type: nlb
    type: LoadBalancer
podDisruptionBudget:
  enabled: true
  minAvailable: 1
# Install with a values file
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace \
  --version 4.9.1 \
  -f ingress-nginx-values.yaml

# Upgrade with updated values (e.g. bumping replicaCount to 3)
helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --version 4.9.1 \
  -f ingress-nginx-values.yaml \
  --atomic                       # Rollback automatically if upgrade fails
  --timeout 5m

# Idempotent: install if not present, upgrade if exists
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace \
  -f ingress-nginx-values.yaml

# Inspect what values are currently active for a release
helm get values ingress-nginx -n ingress-nginx        # User-supplied values only
helm get values ingress-nginx -n ingress-nginx --all  # Including chart defaults
$ helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --version 4.9.1 \
  -f ingress-nginx-values.yaml --atomic
Release "ingress-nginx" has been upgraded. Happy Helming!
REVISION: 2

$ helm history ingress-nginx -n ingress-nginx
REVISION  UPDATED                  STATUS      CHART                  DESCRIPTION
1         2025-03-10 11:04:22      superseded  ingress-nginx-4.9.1   Install complete
2         2025-03-10 11:22:47      deployed    ingress-nginx-4.9.1   Upgrade complete

Rollback

If an upgrade causes problems, rolling back is a single command. Helm re-applies the rendered manifests from the target revision — no manual YAML editing.

# Roll back to revision 1
helm rollback ingress-nginx 1 -n ingress-nginx --wait

# After rollback -- history shows a new revision (history is append-only)
helm history ingress-nginx -n ingress-nginx
# REVISION  STATUS      DESCRIPTION
# 1         superseded  Install complete
# 2         superseded  Upgrade complete
# 3         deployed    Rollback to 1  ← rollback creates revision 3, not a rewind

# See exactly what changed between revisions
helm diff revision ingress-nginx 1 2 -n ingress-nginx   # requires helm-diff plugin

# Uninstall (removes all resources AND history)
helm uninstall ingress-nginx -n ingress-nginx
helm uninstall ingress-nginx -n ingress-nginx --keep-history  # Keep history for audit
$ helm rollback ingress-nginx 1 -n ingress-nginx --wait
Rollback was a success! Happy Helming!

$ helm history ingress-nginx -n ingress-nginx
REVISION  UPDATED                  STATUS      CHART                  DESCRIPTION
1         2025-03-10 11:04:22      superseded  ingress-nginx-4.9.1   Install complete
2         2025-03-10 11:22:47      superseded  ingress-nginx-4.9.1   Upgrade complete
3         2025-03-10 11:35:01      deployed    ingress-nginx-4.9.1   Rollback to 1  ✓

$ helm uninstall ingress-nginx -n ingress-nginx
release "ingress-nginx" uninstalled
# All 10 resources deleted atomically

$ helm uninstall ingress-nginx -n ingress-nginx --keep-history
release "ingress-nginx" uninstalled
$ helm history ingress-nginx -n ingress-nginx
REVISION  STATUS       DESCRIPTION
1         superseded   Install complete
2         superseded   Upgrade complete
3         uninstalled  Uninstallation complete  ← history preserved for audit ✓

Essential Helm Commands Reference

Command What it does
helm repo add / updateRegister and refresh chart repositories
helm search repo / hubFind charts in repos or on Artifact Hub
helm show values <chart>Print all configurable values and defaults
helm install <release> <chart>Install a chart as a named release
helm upgrade --installInstall if absent, upgrade if present (idempotent)
helm list [-n namespace]List all releases in a namespace
helm history <release>Show revision history of a release
helm get values <release>Show values currently applied to a release
helm get manifest <release>Show rendered Kubernetes manifests for a release
helm rollback <release> <rev>Roll back to a specific revision
helm uninstall <release>Delete all release resources and history
helm lint <chart-dir>Validate chart structure and template syntax

Teacher's Note: Helm 2 vs Helm 3

You may encounter references to Helm 2 in older documentation. Helm 3 (released 2019) made two important security improvements: it removed Tiller — an in-cluster server component that had broad cluster-admin permissions and was a significant attack surface. Helm 3 runs entirely client-side using your own kubeconfig credentials. It also moved release state from a ConfigMap in kube-system to Secrets in the release namespace, scoping it properly per namespace rather than cluster-wide.

If you see instructions that say "install Tiller first" — that is Helm 2. Stop and find a Helm 3 guide. Helm 2 reached end-of-life in November 2020. All current charts, documentation, and tooling assume Helm 3.

Practice Questions

1. Which Helm command is idempotent — installing a release if it doesn't exist and upgrading it if it does — making it safe to run repeatedly in CI/CD pipelines?



2. Before installing a third-party chart, you want to see all the configuration options it supports and their default values. Which command shows this?



3. Where does Helm 3 store the rendered manifests for each release revision, enabling rollback without Git access?



Quiz

1. What is the difference between a Helm chart and a Helm release?


2. You upgrade a release to revision 2 and it causes problems. You run helm rollback myapp 1. What does helm history myapp show afterwards?


3. What does the --atomic flag do during a helm upgrade?


Up Next · Lesson 55

Helm Charts

Now that you can use charts, this lesson covers writing them from scratch: chart structure, the Go template engine, named helpers in _helpers.tpl, feature flags for optional resources, and multi-environment values files.