Preface
The evolution of containerization has taken us from Docker to Kubernetes:
Docker era:
- Gentle learning curve — one
docker runboots an app - Single container, simple config, easy to grasp
- Great for small projects and personal dev
Kubernetes era:
- Powerful, but a steep learning curve
- Need to manage many resources (Pod, Service, Deployment, Ingress, etc.)
- File counts explode, maintenance cost is high
- But delivers enterprise-grade scalability, HA, and automation
Enter Helm:
- Makes Kubernetes complexity manageable
- Just as Docker made containers simple, Helm makes K8s deployment simple
- One Chart can manage an entire app's lifecycle
- Easy swapping, clear version management, easy rollback
But Helm brings new challenges too:
- More configuration: on top of YAML, you also learn Chart structure, values.yaml, and template syntax
- Steeper learning curve still: need to understand Go templates, Helm commands, the Chart ecosystem
- Beginners may feel Helm is more complex than plain YAML
- But once you grok it, maintenance and migration costs end up lower
What is Helm? Why do you need it?
Imagine deploying a complete web app on Kubernetes. You'd need:
- Deployment (Pod management)
- Service (network)
- Ingress (external access)
- ConfigMap (configuration)
- Secret (passwords)
If you wrote these YAMLs manually for each environment (dev, staging, prod), you'd find:
❌ Problem 1: file explosion
- Dev: 5 YAML files
- Staging: 5 YAML files
- Prod: 5 YAML files
- 15 files to maintain in total!
❌ Problem 2: parameter chaos
- Dev uses
nginx:1.20, prod usesnginx:1.21 - Dev has 1 replica, prod has 3
- Every release means manually editing a pile of files
❌ Problem 3: hard version management
- When something breaks, you don't know which version to roll back to
- No clear deployment history
How does Helm solve these?
Helm is the "package manager for Kubernetes" — it bundles multiple YAML files into a "Chart":
✅ One Chart for all environments
- Use
values.yamlto control per-environment parameters - Dev:
helm install my-app ./my-chart -f dev-values.yaml - Prod:
helm install my-app ./my-chart -f prod-values.yaml
✅ Versioning and rollback
- Each deployment gets a revision (REVISION 1, 2, 3...)
- When something breaks:
helm rollback my-app 2rolls back instantly
✅ Rich ecosystem
- No need to write Charts yourself — use ready-made ones (MySQL, Redis, Nginx, etc.)
- Like a phone App Store, with thousands of apps
In short: Helm makes deploying apps to K8s as easy as installing apps on your phone!
How does Helm work?
1. A Chart is an "app bundle"
my-web-app/
├── Chart.yaml # App info (name, version)
├── values.yaml # Default settings
├── templates/ # YAML templates
│ ├── deployment.yaml
│ ├── service.yaml
│ └── ingress.yaml
└── charts/ # Other dependent apps
2. Template + values = final YAML
Template (templates/deployment.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.app.name }} # Replaced here
spec:
replicas: {{ .Values.replicas }} # Replaced here
template:
spec:
containers:
- name: {{ .Values.app.name }}
image: {{ .Values.image }}:{{ .Values.tag }}
Values (values.yaml):
app:
name: "my-web-app"
replicas: 3
image: "nginx"
tag: "1.21"
Final YAML produced:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-web-app
spec:
replicas: 3
template:
spec:
containers:
- name: my-web-app
image: nginx:1.21
3. Different values files for different environments
Dev (dev-values.yaml):
replicas: 1
image: "nginx"
tag: "1.20"
Prod (prod-values.yaml):
replicas: 3
image: "nginx"
tag: "1.21"
Hands-on: deploy Elasticsearch in 5 minutes
Step 1: install Helm
# macOS
brew install helm
# Linux
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Windows
choco install kubernetes-helm
Step 2: add Elastic's "app store"
helm repo add elastic https://helm.elastic.co
helm repo update
Step 3: one-command Elasticsearch install
helm install elasticsearch elastic/elasticsearch
That's it! Elasticsearch starts deploying.
Step 4: check deployment status
# List all installed apps
helm list
# Detailed status of Elasticsearch
helm status elasticsearch
# Deployment history
helm history elasticsearch
Step 5: upgrade or roll back
# Upgrade to a new version
helm upgrade elasticsearch elastic/elasticsearch --set imageTag=8.5.0
# If broken, roll back to previous
helm rollback elasticsearch
Helm vs raw YAML: side-by-side
Deploying Nginx with raw YAML
deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-dev
spec:
replicas: 1
template:
spec:
containers:
- name: nginx
image: nginx:1.20
service.yaml:
apiVersion: v1
kind: Service
metadata:
name: nginx-dev-service
spec:
selector:
app: nginx-dev
ports:
- port: 80
Prod requires another similar set of files...
Deploying Nginx with Helm
One command does it:
# Dev
helm install nginx bitnami/nginx --set replicaCount=1,imageTag=1.20
# Prod
helm install nginx bitnami/nginx --set replicaCount=3,imageTag=1.21
Comparison:
| Item | Raw YAML | Helm |
|---|---|---|
| File count | envs × resources | 1 Chart |
| Parameter mgmt | Edit each file by hand | Unified values.yaml |
| Versioning | Manual logs | Auto version mgmt |
| Rollback | Manual rebuild | helm rollback |
| Ecosystem | Write your own | Thousands of ready Charts |
Common Helm commands
# Basics
helm list # List installed apps
helm status <app-name> # App status
helm history <app-name> # Deployment history
# Install and upgrade
helm install <name> <chart> # Install
helm upgrade <name> <chart> # Upgrade
helm uninstall <name> # Uninstall
# Rollback
helm rollback <name> <revision> # Rollback to specific revision
helm rollback <name> # Rollback to previous
# View and download
helm search repo <keyword> # Search available Charts
helm pull <chart> # Download Chart locally
helm template <chart> # Preview generated YAML
How is Helm Rollback implemented?
A common question: how does helm rollback roll back so quickly? The mechanism isn't complex.
Release and Revision mechanism
Each helm install or helm upgrade creates a Release with a Revision number:
# View deployment history
helm history my-app
# Sample output:
REVISION STATUS CHART DESCRIPTION
1 superseded my-app-1.0.0 Install complete
2 superseded my-app-1.0.1 Upgrade complete
3 deployed my-app-1.0.2 Upgrade complete
Where is the historical data stored?
Helm stores the complete info for each Revision in Kubernetes Secrets:
# View Helm-created Secrets
kubectl get secrets -l owner=helm
# Sample output:
NAME TYPE DATA
sh.helm.release.v1.my-app.v1 helm.sh/release.v1 1
sh.helm.release.v1.my-app.v2 helm.sh/release.v1 1
sh.helm.release.v1.my-app.v3 helm.sh/release.v1 1
Each Secret contains:
- Chart templates: all YAML templates used at the time
- Values: settings used at the time
- Manifest: final Kubernetes resource YAML produced
- Metadata: revision number, status, timestamps, etc.
How Rollback works
When you run helm rollback my-app 2, Helm:
┌─────────────────────────────────────────────────────────┐
│ 1. Read target revision │
│ Pull data from Secret sh.helm.release.v1.my-app.v2 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 2. Decompress and decode │
│ Secret content is base64 + gzip compressed │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 3. Get the old manifest │
│ Obtain the complete Kubernetes YAML produced then │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 4. Three-way merge │
│ Compare: old manifest vs current state vs target │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 5. Apply changes │
│ kubectl apply updates resources to target state │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 6. Create a new Revision │
│ Rollback itself creates a new revision (e.g., v4) │
└─────────────────────────────────────────────────────────┘
Real example: viewing Secret contents
# Get a specific Release version's data
kubectl get secret sh.helm.release.v1.my-app.v2 -o jsonpath='{.data.release}' | base64 -d | gunzip
# Outputs the complete Release info as JSON, including:
# - chart: complete Chart contents
# - config: values at the time
# - manifest: produced YAML
# - version: revision number
Why is Rollback so fast?
- No Chart re-download: all data is in the Secret
- No template re-render: the Manifest is pre-rendered
- Only diffed resources updated: three-way merge processes only what truly needs to change
Caveats
⚠️ Secret size limit: Kubernetes Secret defaults to 1MB max — large Charts may have issues
⚠️ Historical revisions accumulate: defaults to keeping 10 — adjust via --history-max:
helm upgrade my-app ./my-chart --history-max 5
⚠️ Rollback doesn't restore data: only restores Kubernetes resource configs — databases and other persistent data don't roll back
Difference from Kubernetes-native Rollback
| Item | Helm Rollback | kubectl rollout undo |
|---|---|---|
| Scope | Whole Release (multiple resources) | Single Deployment |
| History storage | Kubernetes Secret | ReplicaSet |
| Config restore | Full restore (incl. values) | Only Pod template |
| ConfigMap/Secret | ✅ Restored | ❌ Not restored |
Helm versions vs Git
A common question: "How do Helm Revisions relate to Git commits?"
Answer: they're entirely separate systems with no direct relationship.
┌─────────────────────────────────────────────────────────────────┐
│ Two independent versioning systems │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Git (source code version control) Helm (deploy versioning) │
│ ├── commit abc123 ├── Revision 1 │
│ ├── commit def456 ├── Revision 2 │
│ ├── commit ghi789 ├── Revision 3 │
│ └── stored in Git Repository └── stored in K8s Secret │
│ │
└─────────────────────────────────────────────────────────────────┘
They track different things:
| Item | Git | Helm Revision |
|---|---|---|
| Tracks | Source code changes | Deployment-state changes |
| Storage | Git Repository | Kubernetes Secret |
| Version format | SHA hash (like abc123) | Incrementing number (1, 2, 3...) |
| Rollback effect | Code goes back in time | K8s resources go back in time |
Why are they independent?
-
Deployments don't always correspond to code changes
- You might just change
replicas: 3→replicas: 5(no code change) - Helm gets a new Revision; Git gets no new commit
- You might just change
-
One commit may be deployed many times
- The same code version may be deployed to dev, staging, prod
- Each deployment is a new Helm Revision
-
Deployments may fail and retry
- Same commit may be deployed multiple times due to settings tweaks
How are they linked in practice?
Even though they're independent, in CI/CD we typically link them via Labels or Annotations:
# Add Git info in values.yaml or at deploy time
metadata:
annotations:
git.commit: "abc123def"
git.branch: "main"
git.repo: "github.com/myorg/myapp"
Inject Git info at deploy time:
# Auto-inject Git commit in CI/CD
helm upgrade my-app ./chart \
--set gitCommit=$(git rev-parse --short HEAD) \
--set gitBranch=$(git branch --show-current)
Benefits:
- When something breaks, quickly trace which commit caused it
- Easier to track "which code version this deployment corresponds to"
- But Rollback still uses Helm Revision, not Git commit
Summary: By storing every revision's complete info in a Secret, Helm achieves fast and complete rollback. That's also why Helm is more reliable than hand-managing YAML.
Where to find ready-made Charts?
1. Artifact Hub (most recommended)
- URL: https://artifacthub.io/
- Like Helm's "App Store"
- Thousands of apps you can use directly
2. Bitnami Charts (high quality)
- URL: https://charts.bitnami.com/bitnami
- Maintained by VMware, stable quality
- Includes MySQL, Redis, Kafka, and other common services
3. Official Charts
- Elastic: https://helm.elastic.co
- Grafana: https://grafana.github.io/helm-charts
- Prometheus: https://prometheus-community.github.io/helm-charts
How to choose a good Chart?
- Maintenance status: updated within the last 6 months
- Download count: high downloads usually means more stable
- Documentation: complete usage instructions
- Community: active discussion on GitHub
Practical advice
1. Start simple
- Try ready-made Charts first (Nginx, Redis)
- Once familiar, consider building your own
2. Environment separation
- Use different values.yaml for dev/staging/prod
- Don't directly modify Chart source files
3. Version control
- Put values.yaml under Git management
- Record version numbers for each deployment
4. Back up important data
- Databases and other critical services need regular backups
- Helm only manages app deployment, not data backups
FAQ
Q: Will Helm affect existing Kubernetes resources? A: No. Helm is a management tool only — it won't affect existing resources.
Q: Can I use Helm and kubectl together? A: Yes. Helm ultimately interacts with Kubernetes via kubectl.
Q: What if a Chart has problems?
A: Use helm rollback to roll back, or helm uninstall to remove and reinstall.
Q: Is building your own Chart complicated? A: It can feel complex at first, but once familiar it's much simpler than hand-writing YAML.
Summary
Helm makes Kubernetes app deployment:
- Simpler: deploy complex apps with one command
- Safer: version management and quick rollback
- More efficient: reuse existing Charts — don't reinvent the wheel
If you're still hand-writing piles of YAML, give Helm a try — you'll discover a new world!
References
- Artifact Hub — Helm Chart search platform
- Bitnami Charts — High-quality Chart collection
- Elastic Helm Charts — Official Elastic Charts




























Comments