Helm Cheatsheet
Quick reference for Helm — the Kubernetes package manager. Covers installation, chart management, templating, OCI registries, and production patterns.
Quick Reference
Installation & Setup
# Install Helm (Linux/macOS)
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# macOS via Homebrew
brew install helm
# Verify installation
helm version
helm env
# Set default namespace
export HELM_NAMESPACE=production
Repository Management
# Add popular repos
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add stable https://charts.helm.sh/stable
helm repo add jetstack https://charts.jetstack.io
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
# Update all repos
helm repo update
# List configured repos
helm repo list
# Remove a repo
helm repo remove stable
# Search in repos
helm search repo nginx
helm search repo bitnami/nginx --versions
Chart Operations
# Install a chart
helm install my-release bitnami/nginx -n my-ns
# Install with values file
helm install my-release bitnami/nginx -f values.yaml
# Upgrade (or install if not exists)
helm upgrade --install my-release bitnami/nginx \
--namespace my-ns --create-namespace \
-f values.yaml
# Uninstall a release
helm uninstall my-release -n my-ns
# Rollback to previous revision
helm rollback my-release 1 -n my-ns
# View release history
helm history my-release -n my-ns
Release Management
# List all releases (all namespaces)
helm list -A
helm list --all-namespaces
# Filter by state
helm list -A --deployed
helm list -A --failed
helm list -A --pending
# Get release status
helm status my-release -n my-ns
# Get deployed values
helm get values my-release -n my-ns
helm get values my-release -n my-ns --all # includes defaults
# Get manifest / hooks / notes
helm get manifest my-release -n my-ns
helm get hooks my-release -n my-ns
helm get notes my-release -n my-ns
Templating & Debugging
# Render templates locally (no cluster)
helm template my-release ./mychart -f values.yaml
# Render with namespace context
helm template my-release ./mychart \
--namespace production \
--set image.tag=1.2.3
# Lint a chart
helm lint ./mychart
helm lint ./mychart -f values.yaml
# Dry run (server-side validation)
helm install my-release ./mychart --dry-run --debug
# Diff plugin (show what will change)
helm plugin install https://github.com/databus23/helm-diff
helm diff upgrade my-release ./mychart -f values.yaml
Chart Development
# Create new chart scaffold
helm create mychart
# Chart directory structure
mychart/
Chart.yaml # Chart metadata
values.yaml # Default values
charts/ # Chart dependencies
templates/ # Kubernetes manifests
deployment.yaml
service.yaml
ingress.yaml
_helpers.tpl # Named templates
NOTES.txt # Post-install notes
.helmignore # Files to exclude
# Package a chart
helm package ./mychart
helm package ./mychart --version 1.2.3
Show Chart Info
# Show default values
helm show values bitnami/nginx
helm show values bitnami/nginx > values-defaults.yaml
# Show chart metadata
helm show chart bitnami/nginx
# Show README
helm show readme bitnami/nginx
# Show all info
helm show all bitnami/nginx
# Pull chart tarball locally
helm pull bitnami/nginx
helm pull bitnami/nginx --untar
helm pull bitnami/nginx --version 15.0.0 --untar
OCI Registry
# Login to GHCR
helm registry login ghcr.io \
-u USERNAME --password-stdin << EOF
ghp_TOKEN
EOF
# Login to ECR
aws ecr get-login-password --region us-east-1 \
| helm registry login \
--username AWS \
--password-stdin \
123456789.dkr.ecr.us-east-1.amazonaws.com
# Push chart to OCI registry
helm push mychart-1.0.0.tgz oci://ghcr.io/myorg/charts
# Pull from OCI registry
helm pull oci://ghcr.io/myorg/charts/mychart --version 1.0.0
# Install directly from OCI
helm install my-release \
oci://ghcr.io/myorg/charts/mychart \
--version 1.0.0
Values Override Patterns
Helm applies values in order of increasing precedence: chart defaults → -f file flags (left to right) → --set flags.
# --set: simple key=value (highest precedence)
helm upgrade --install my-release ./chart \
--set image.repository=myrepo/myapp \
--set image.tag=v1.2.3 \
--set replicaCount=3
# --set-string: force string type (useful for numeric-looking values)
helm install my-release ./chart \
--set-string image.tag=007 \
--set-string annotations."app\.kubernetes\.io/version"=latest
# --set-json: pass JSON values (arrays, objects)
helm install my-release ./chart \
--set-json 'tolerations=[{"key":"dedicated","operator":"Equal","value":"gpu"}]'
# --values / -f: load from file
helm upgrade --install my-release ./chart \
-f values-base.yaml \
-f values-production.yaml \
--set image.tag=$(git rev-parse --short HEAD)
# Multiple -f flags (right file wins on conflict)
helm upgrade --install my-release ./chart \
-f ./environments/base/values.yaml \
-f ./environments/prod/values.yaml \
-f ./secrets/prod-secrets.yaml
# Precedence order (lowest to highest):
# 1. Chart's values.yaml (defaults)
# 2. Parent chart's values.yaml
# 3. -f files (left to right)
# 4. --set / --set-string / --set-json (rightmost wins)
Complete Chart.yaml Example
apiVersion: v2
name: mychart
description: A Helm chart for my application
type: application # or "library"
version: 1.2.3 # Chart version (SemVer)
appVersion: "2.5.1" # App version (informational)
# Optional fields
icon: https://example.com/icon.png
home: https://example.com
sources:
- https://github.com/myorg/myapp
keywords:
- myapp
- web
maintainers:
- name: Binh Phuong
email: [email protected]
url: https://lebinhphuong.tech
annotations:
artifacthub.io/changes: |
- kind: added
description: Added support for PodDisruptionBudget
# Chart dependencies (stored in charts/ after helm dep update)
dependencies:
- name: postgresql
version: "12.x.x"
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
tags:
- database
- name: redis
version: "17.x.x"
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
Helm Hooks
Hooks execute at specific points in a release lifecycle. Common uses: run DB migrations before upgrade, send notifications after install, clean up jobs before delete.
# Hook annotations reference
annotations:
"helm.sh/hook": pre-install # Before first install
"helm.sh/hook": post-install # After first install
"helm.sh/hook": pre-upgrade # Before upgrade
"helm.sh/hook": post-upgrade # After upgrade
"helm.sh/hook": pre-delete # Before uninstall
"helm.sh/hook": post-delete # After uninstall
"helm.sh/hook": pre-rollback # Before rollback
"helm.sh/hook": post-rollback # After rollback
"helm.sh/hook": test # helm test command
"helm.sh/hook-weight": "-5" # Order (lower = earlier)
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
DB Migration Hook Job Example
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "mychart.fullname" . }}-migrate
annotations:
"helm.sh/hook": pre-upgrade,pre-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
command: ["python", "manage.py", "migrate"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-db-secret
key: url
backoffLimit: 3
Helm Tests
# Run tests for a release
helm test my-release -n my-ns
helm test my-release -n my-ns --logs
# Test Pod template (place in templates/tests/)
apiVersion: v1
kind: Pod
metadata:
name: {{ include "mychart.fullname" . }}-test-connection
annotations:
"helm.sh/hook": test
spec:
restartPolicy: Never
containers:
- name: wget
image: busybox
command: ['wget']
args:
- '--spider'
- 'http://{{ include "mychart.fullname" . }}:{{ .Values.service.port }}/healthz'
Common Helm Patterns
Subcharts & Dependencies
# Download dependencies declared in Chart.yaml
helm dependency update ./mychart
helm dependency build ./mychart # use Chart.lock (reproducible)
helm dependency list ./mychart
# Override subchart values in parent values.yaml:
# values.yaml
postgresql:
enabled: true
auth:
database: myapp
username: myuser
primary:
persistence:
size: 20Gi
redis:
enabled: true
architecture: standalone
Library Charts
# Chart.yaml for a library chart
apiVersion: v2
name: mylib
type: library # Cannot be installed directly
version: 0.1.0
# Use in _helpers.tpl of consumer chart:
{{- define "mylib.labels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
Helmfile Usage
# helmfile.yaml example
repositories:
- name: bitnami
url: https://charts.bitnami.com/bitnami
- name: ingress-nginx
url: https://kubernetes.github.io/ingress-nginx
releases:
- name: ingress-nginx
namespace: ingress-nginx
createNamespace: true
chart: ingress-nginx/ingress-nginx
version: 4.9.0
values:
- ./values/ingress-nginx.yaml
- name: myapp
namespace: production
chart: ./charts/myapp
version: 1.2.3
values:
- ./values/myapp-base.yaml
- ./values/myapp-prod.yaml
secrets:
- ./secrets/myapp-prod.yaml # helm-secrets integration
# Common helmfile commands
helmfile sync # Apply all releases
helmfile diff # Show pending changes
helmfile apply # Sync only changed releases
helmfile destroy # Uninstall all releases
helmfile -l name=myapp sync # Target specific release
Production Tips
Tip — Immutable Image Tags: Always pin
image.tag to a specific SHA or semver tag in production. Never use latest — it makes rollbacks impossible and breaks reproducibility.
# In CI/CD pipeline, set tag to git commit SHA
IMAGE_TAG=$(git rev-parse --short HEAD)
helm upgrade --install myapp ./chart \
--set image.tag=${IMAGE_TAG} \
--atomic --timeout 5m \
--wait
Resource Limits in Charts
# Always provide defaults in values.yaml
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
# In templates/deployment.yaml:
resources:
{{- toYaml .Values.resources | nindent 10 }}
Values Validation with JSON Schema
# Create values.schema.json in chart root
{
"$schema": "https://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["image", "replicaCount"],
"properties": {
"replicaCount": {
"type": "integer",
"minimum": 1,
"maximum": 50
},
"image": {
"type": "object",
"required": ["repository", "tag"],
"properties": {
"repository": { "type": "string" },
"tag": { "type": "string" },
"pullPolicy": {
"type": "string",
"enum": ["Always", "IfNotPresent", "Never"]
}
}
}
}
}
# Helm validates values against schema on install/upgrade
Warning: Avoid
helm upgrade without --atomic in production pipelines. Without it, a failed upgrade leaves the release in a broken state. Use --atomic --timeout 5m to auto-rollback on failure.