Getting Started With Helm 3
Helm is the package manager for Kubernetes — the same idea as apt on Ubuntu or npm in Node.js, but for deploying applications to your cluster. Instead of writing and maintaining dozens of raw Kubernetes YAML files per application, you define a chart once, parameterise it with values, and deploy it consistently across every environment.
Note: Helm 4 was released in 2025 with breaking changes. This guide covers Helm 3, which remains widely used and supported.
What Helm Solves
Without Helm, deploying an application to Kubernetes means manually managing a Deployment, a Service, a ConfigMap, an Ingress, HPA rules, and more — often duplicated across dev, staging, and production with small differences. Any change means updating multiple files manually.
Helm wraps all of that into a single versioned package:
flowchart LR
Chart[Helm Chart\nTemplates + Values] --> Render[Template Engine\nGo templates]
Render --> K8s[Kubernetes Manifests\nDeployment Service Ingress etc]
K8s --> Cluster[Kubernetes Cluster]
Values[values.yaml\nEnvironment overrides] --> Render
Key benefits:
- Repeatability — same chart, same result every time
- Versioning — upgrade and rollback with a single command
- Templating — one chart, multiple environments via values override
- Sharing — push to a chart repository, share with your team
- Lifecycle management — install, upgrade, rollback, uninstall all tracked
Installing Helm
macOS:
brew install helm
Linux:
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Windows (Chocolatey):
choco install kubernetes-helm
Verify:
helm version
Core Concepts
| Term | What it means |
|---|---|
| Chart | A package of Kubernetes resource templates + default values |
| Release | A running instance of a chart in your cluster |
| Repository | A server hosting a collection of charts |
| Values | Configuration that overrides chart defaults at install time |
| Revision | A numbered snapshot of a release — every upgrade creates a new revision |
Working with Chart Repositories
Helm Artifact Hub (artifacthub.io) is the central index for public charts.
# Add a repository
helm repo add bitnami https://charts.bitnami.com/bitnami
# Update local cache
helm repo update
# Search for a chart
helm search repo bitnami/postgresql
# List all configured repos
helm repo list
Install a chart from a repository:
# Install with auto-generated name
helm install bitnami/nginx --generate-name
# Install with a specific release name
helm install my-nginx bitnami/nginx
# Install with value overrides
helm install my-nginx bitnami/nginx \
--set service.type=LoadBalancer \
--set replicaCount=2
Creating Your Own Chart
helm create my-app
This generates the following structure:
my-app/
├── Chart.yaml # Chart metadata: name, version, description
├── values.yaml # Default configuration values
├── templates/ # Kubernetes resource templates
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── _helpers.tpl # Reusable template snippets
│ └── NOTES.txt # Post-install notes shown to the user
└── charts/ # Sub-chart dependencies
Chart.yaml
apiVersion: v2
name: my-app
description: A Helm chart for my application
type: application
version: 0.1.0 # Chart version — increment on chart changes
appVersion: "1.0.0" # Application version being packaged
values.yaml
replicaCount: 2
image:
repository: my-registry/my-app
tag: "latest"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 250m
memory: 64Mi
ingress:
enabled: false
host: my-app.example.com
Deployment template
Values are injected using Go template syntax with {{ }} directives:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-app.fullname" . }}
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: {{ .Values.service.port }}
The Release Lifecycle
sequenceDiagram
participant Dev as Developer
participant Helm as Helm CLI
participant K8s as Kubernetes
Dev->>Helm: helm install my-app ./my-app
Helm->>K8s: Apply rendered manifests
K8s-->>Helm: Release v1 created
Helm-->>Dev: Installed - revision 1
Dev->>Helm: helm upgrade my-app ./my-app --set image.tag=v2
Helm->>K8s: Apply updated manifests
K8s-->>Helm: Rolling update complete
Helm-->>Dev: Upgraded - revision 2
Dev->>Helm: helm rollback my-app 1
Helm->>K8s: Restore revision 1 manifests
Helm-->>Dev: Rolled back to revision 1
# Install
helm install my-release ./my-app
# Upgrade (with value override for production)
helm upgrade my-release ./my-app -f values.prod.yaml
# Preview what would change (dry run)
helm upgrade my-release ./my-app --dry-run --debug
# Check release status
helm status my-release
# View history
helm history my-release
# Rollback to previous revision
helm rollback my-release 1
# Uninstall
helm uninstall my-release
Environment-Specific Values
The clean pattern for multi-environment deployments is a base values.yaml with environment-specific override files:
my-app/
├── values.yaml # base defaults
├── values.dev.yaml # dev overrides
├── values.staging.yaml # staging overrides
└── values.prod.yaml # production overrides
values.prod.yaml:
replicaCount: 5
image:
tag: "1.4.2"
resources:
limits:
cpu: 2000m
memory: 1Gi
ingress:
enabled: true
host: app.example.com
Deploy to production:
helm upgrade --install my-app ./my-app -f values.prod.yaml
The --install flag makes upgrade behave like install if the release does not exist yet — useful in CI/CD pipelines where you do not know whether this is a first deploy or an update.
Essential Commands Reference
| Command | What it does |
|---|---|
helm install <name> <chart> | Install a chart as a new release |
helm upgrade <name> <chart> | Upgrade an existing release |
helm upgrade --install <name> <chart> | Install or upgrade (CI-safe) |
helm rollback <name> <revision> | Roll back to a previous revision |
helm uninstall <name> | Remove a release |
helm list | List all releases |
helm status <name> | Show release status |
helm history <name> | Show release history |
helm template <name> <chart> | Render templates without installing |
helm lint <chart> | Validate a chart for errors |
helm package <chart> | Package chart into a .tgz file |
helm get values <name> | Show values used for a release |
Demo Project
A working Helm chart is available on GitHub: devops-monk/helm-demo-project
Clone it and follow along with the commands above to see Helm in action against a real chart.
