Advertisementslot: not configuredSet AdSense publisher and slot env vars in .env.local

Helm — The Kubernetes Package Manager

Helm is the de-facto package manager for Kubernetes. It packages K8s manifests into reusable charts, tracks deployed releases, and supports rollbacks.


Core Concepts

Term Description
Chart A package of K8s templates + default values
Release A deployed instance of a chart (you can deploy the same chart multiple times)
Repository A HTTP server hosting charts (like npm registry)
Values YAML configuration that overrides chart defaults
Template Go-templated K8s manifest inside a chart

Installation

# macOS
brew install helm

# Linux
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# Verify
helm version

Repository Management

# Add popular repos
helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo add cert-manager https://charts.jetstack.io
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add argo https://argoproj.github.io/argo-helm

# Update all repos (like apt-get update)
helm repo update

# Search for a chart
helm search repo nginx
helm search repo bitnami/postgres
helm search hub wordpress        # search ArtifactHub (public index)

# Show available versions
helm search repo bitnami/postgresql --versions | head -10

Installing Charts

# Basic install
helm install my-nginx bitnami/nginx

# Install into a specific namespace (creates namespace if --create-namespace)
helm install my-nginx bitnami/nginx -n web --create-namespace

# Override values inline
helm install my-nginx bitnami/nginx \
  --set replicaCount=3 \
  --set service.type=LoadBalancer

# Override with a values file (recommended for complex config)
helm install my-nginx bitnami/nginx -f values-prod.yaml

# Combine file + inline (inline wins on conflicts)
helm install my-nginx bitnami/nginx -f values-prod.yaml --set image.tag=1.27

# Install specific version
helm install my-nginx bitnami/nginx --version 15.3.5

# Dry run (show what would be deployed without applying)
helm install my-nginx bitnami/nginx --dry-run --debug

# Wait until deployment is ready
helm install my-nginx bitnami/nginx --wait --timeout 5m

Managing Releases

# List releases
helm list
helm list -n web
helm list -A              # all namespaces
helm list --failed        # only failed releases

# Check release status
helm status my-nginx

# Show release history (rollback targets)
helm history my-nginx

# Upgrade (update config or chart version)
helm upgrade my-nginx bitnami/nginx --set replicaCount=5
helm upgrade my-nginx bitnami/nginx -f values-prod.yaml --version 15.4.0

# Install OR upgrade (idempotent — great for CI/CD)
helm upgrade --install my-nginx bitnami/nginx -f values-prod.yaml -n web --create-namespace

# Rollback to a previous revision
helm rollback my-nginx 1         # rollback to revision 1
helm rollback my-nginx           # rollback to previous revision

# Uninstall (keeps history by default)
helm uninstall my-nginx
helm uninstall my-nginx --keep-history   # keep history for rollback

Inspecting Charts

# Show default values
helm show values bitnami/nginx
helm show values bitnami/nginx > values.yaml    # save to file for customization

# Show chart metadata
helm show chart bitnami/nginx

# Show all chart info (values + chart + README)
helm show all bitnami/nginx

# Show what will be deployed (render templates locally)
helm template my-nginx bitnami/nginx -f values.yaml

# Show differences before upgrade
helm diff upgrade my-nginx bitnami/nginx -f values.yaml   # requires helm-diff plugin

Creating Your Own Chart

# Scaffold a new chart
helm create myapp

# Structure created:
# myapp/
# ├── Chart.yaml          # chart metadata (name, version, appVersion)
# ├── values.yaml         # default configuration
# ├── charts/             # chart dependencies
# └── templates/
#     ├── deployment.yaml
#     ├── service.yaml
#     ├── ingress.yaml
#     ├── serviceaccount.yaml
#     ├── hpa.yaml
#     ├── NOTES.txt       # shown after install
#     └── _helpers.tpl    # reusable template snippets

Chart.yaml

apiVersion: v2
name: myapp
description: My application Helm chart
type: application
version: 1.0.0        # chart version — bump on chart changes
appVersion: "2.3.1"   # application version (informational)
dependencies:
- name: postgresql
  version: "12.x.x"
  repository: https://charts.bitnami.com/bitnami
  condition: postgresql.enabled

values.yaml

replicaCount: 2

image:
  repository: myregistry/myapp
  tag: "2.3.1"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
  className: nginx
  host: myapp.example.com

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

autoscaling:
  enabled: false
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70

postgresql:
  enabled: true
  auth:
    database: myapp
    username: myapp
    existingSecret: db-secret

templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "myapp.fullname" . }}
  labels:
    {{- include "myapp.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "myapp.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "myapp.selectorLabels" . | nindent 8 }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: 80
        resources:
          {{- toYaml .Values.resources | nindent 10 }}
        env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: password

_helpers.tpl (reusable snippets)

{{/*
Expand the name of the chart.
*/}}
{{- define "myapp.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Full name  release + chart name
*/}}
{{- define "myapp.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name (include "myapp.name" .) | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "myapp.labels" -}}
helm.sh/chart: {{ include "myapp.chart" . }}
{{ include "myapp.selectorLabels" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "myapp.selectorLabels" -}}
app.kubernetes.io/name: {{ include "myapp.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

Chart Dependencies

# Download dependencies defined in Chart.yaml
helm dependency update myapp/

# List dependencies
helm dependency list myapp/

Packaging & Publishing

# Lint a chart (check for errors)
helm lint myapp/

# Package chart into .tgz
helm package myapp/
# → myapp-1.0.0.tgz

# Push to OCI registry (Helm 3.8+)
helm push myapp-1.0.0.tgz oci://registry.example.com/charts

# Install from OCI
helm install myapp oci://registry.example.com/charts/myapp --version 1.0.0

# Host a chart repo (serve directory as HTTP)
helm repo index ./charts --url https://charts.example.com

Useful Helm Plugins

# helm-diff — show diff before upgrade
helm plugin install https://github.com/databus23/helm-diff
helm diff upgrade my-nginx bitnami/nginx -f values.yaml

# helm-secrets — encrypt values with SOPS/Vault
helm plugin install https://github.com/jkroepke/helm-secrets

# helm-unittest — unit test chart templates
helm plugin install https://github.com/helm-unittest/helm-unittest

Helm in CI/CD (Best Practices)

# Always use --atomic in CI (rolls back on failure)
helm upgrade --install myapp ./charts/myapp \
  -f values-prod.yaml \
  --namespace production \
  --create-namespace \
  --atomic \
  --timeout 10m \
  --wait

# Set image tag from CI pipeline variable
helm upgrade --install myapp ./charts/myapp \
  --set image.tag=$CI_COMMIT_SHA \
  -f values-prod.yaml

# Use --reuse-values to preserve existing config when bumping chart version
helm upgrade myapp bitnami/nginx --reuse-values --version 15.5.0

Common Interview Questions

Q: Difference between helm install and helm upgrade --install?

helm install fails if the release already exists. helm upgrade --install creates it if missing or upgrades if it exists — idempotent and preferred in CI/CD.

Q: How do you manage secrets in Helm?

Don't put raw secrets in values files. Options: (1) Reference existing K8s Secrets by name in values, (2) Use helm-secrets plugin with SOPS/Vault, (3) Use External Secrets Operator, (4) Pass --set db.password=$SECRET from CI env vars.

Q: What is the difference between chart version and appVersion?

version is the Helm chart version — bump it when you change templates or values schema. appVersion is the deployed application version — informational only, used by default as the image tag.

Q: How do you roll back a Helm release?

helm rollback <release> <revision>. Helm stores all revision history in the cluster (as Secrets). View with helm history <release>.

Advertisementslot: not configuredSet AdSense publisher and slot env vars in .env.local
Use the sidebar to navigate between topics.