Introduction
Helm is the package manager for Kubernetes. Just as apt manages packages on Ubuntu or npm manages Node.js dependencies, Helm manages Kubernetes application deployments. Without Helm, deploying even a simple application requires maintaining dozens of YAML files manually. With Helm, you create charts (packages) that can be versioned, shared, and deployed with a single command. This guide teaches you to use and create Helm charts professionally.
Installing Helm
# Install Helm (Linux)
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Verify
helm version
# version.BuildInfo{Version:"v3.13.3", ...}
# Add common repositories
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 updateUsing Existing Helm Charts
# Search for charts
helm search repo nginx
helm search hub redis # Search Artifact Hub (public registry)
# Install nginx ingress controller
helm install nginx-ingress ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace --set controller.replicaCount=2 --set controller.service.type=LoadBalancer
# Install with values file
helm install my-redis bitnami/redis --namespace databases --create-namespace -f redis-values.yaml
# Check status
helm list -A # List all releases
helm status my-redis -n databases
helm get values my-redis -n databases # See current values
# Upgrade a release
helm upgrade my-redis bitnami/redis --namespace databases --reuse-values --set auth.password=newpassword
# Rollback to previous version
helm rollback my-redis 1 -n databases
# Uninstall
helm uninstall my-redis -n databasesCreating Your First Helm Chart
# Scaffold a new chart
helm create myappThis creates:
myapp/
├── Chart.yaml # Chart metadata
├── values.yaml # Default values
├── charts/ # Chart dependencies
└── templates/ # Kubernetes manifest templates
├── deployment.yaml
├── service.yaml
├── ingress.yaml
├── hpa.yaml
├── serviceaccount.yaml
├── _helpers.tpl # Template helper functions
└── NOTES.txt # Post-install instructionsChart.yaml
# Chart.yaml
apiVersion: v2
name: myapp
description: My production web application
type: application
version: 1.2.0 # Chart version (bump when chart changes)
appVersion: "3.5.1" # Application version being packaged
dependencies:
- name: redis
version: "~18.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabledWriting Templates
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
labels:
{{- include "myapp.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
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 }}"
ports:
- containerPort: {{ .Values.service.port }}
env:
{{- range $key, $val := .Values.env }}
- name: {{ $key }}
value: {{ $val | quote }}
{{- end }}
{{- if .Values.resources }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- end }}
{{- if .Values.configMap.enabled }}
envFrom:
- configMapRef:
name: {{ include "myapp.fullname" . }}-config
{{- end }}values.yaml
# values.yaml
replicaCount: 2
image:
repository: company/myapp
pullPolicy: IfNotPresent
tag: "" # Defaults to Chart.appVersion
service:
type: ClusterIP
port: 8080
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: app.company.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: app-tls
hosts:
- app.company.com
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
autoscaling:
enabled: false
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 80
env:
LOG_LEVEL: "info"
DATABASE_URL: "postgresql://app:pass@postgres:5432/appdb"
configMap:
enabled: false
redis:
enabled: false
auth:
password: "changeme"Template Helper Functions (_helpers.tpl)
{{/* templates/_helpers.tpl */}}
{{/* Expand chart name */}}
{{- define "myapp.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/* Create full name */}}
{{- define "myapp.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- printf "%s-%s" .Release.Name $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 }}Environment-Specific Values
# values-production.yaml
replicaCount: 10
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
autoscaling:
enabled: true
minReplicas: 5
maxReplicas: 50
# values-staging.yaml
replicaCount: 2
resources:
requests:
cpu: 100m
memory: 128Mi# Deploy to staging
helm upgrade --install myapp ./myapp -f values.yaml -f values-staging.yaml --namespace staging --create-namespace
# Deploy to production
helm upgrade --install myapp ./myapp -f values.yaml -f values-production.yaml --namespace production --set image.tag=v3.5.2Debugging and Testing
# Render templates without deploying
helm template myapp ./myapp -f values.yaml
# Validate rendered templates
helm template myapp ./myapp | kubectl apply --dry-run=client -f -
# Lint chart
helm lint ./myapp
# Debug: show computed values
helm install myapp ./myapp --debug --dry-run
# After deployment: view rendered templates that were applied
helm get manifest myapp -n productionPackaging and Publishing
# Package chart
helm package ./myapp
# Creates: myapp-1.2.0.tgz
# Create chart repository index
helm repo index . --url https://charts.company.com
# Upload to GitHub Pages (simple approach)
git add myapp-1.2.0.tgz index.yaml
git commit -m "Release myapp v1.2.0"
git push
# Or push to OCI registry (modern approach)
helm push myapp-1.2.0.tgz oci://registry.company.com/helm-chartsHelm charts transform ad-hoc Kubernetes deployments into repeatable, version-controlled releases. Start by using community charts for databases and infrastructure, then create your own charts for application deployments.
