Introduction to Helm - The Kubernetes Package Manager
Helm streamlines the deployment and management of Kubernetes applications by packaging all necessary resources into reusable charts. Rather than managing dozens of YAML files manually, Helm enables teams to define, install, and upgrade complex applications with simple commands. This approach transforms Kubernetes deployments from error-prone manual processes into reproducible, version-controlled operations.
What Is Helm?
Helm serves as a package manager for Kubernetes, similar to apt for Ubuntu, yum for Red Hat, or npm for Node.js. It bundles Kubernetes manifests into charts - versioned packages that can be installed, upgraded, and shared across teams and organizations.
graph TB
A[Helm] --> B[Package Management]
A --> C[Templating]
A --> D[Release Management]
B --> B1[Charts
Reusable packages]
B --> B2[Repositories
Chart distribution]
B --> B3[Dependencies
Chart relationships]
C --> C1[Values
Configuration]
C --> C2[Templates
Dynamic manifests]
C --> C3[Functions
Logic & helpers]
D --> D1[Versions
Track releases]
D --> D2[Upgrades
Update deployments]
D --> D3[Rollbacks
Revert changes]
Core Capabilities:
- Packaging: Bundle related Kubernetes resources together
- Templating: Generate manifests dynamically based on values
- Versioning: Track and manage application releases
- Dependency Management: Handle multi-tier applications
- Sharing: Distribute charts through repositories
Helm Architecture
Helm 3 (the current major version) uses a client-only architecture that communicates directly with the Kubernetes API:
sequenceDiagram
participant User
participant Helm as Helm Client
participant K8s as Kubernetes API
participant Storage as K8s Secret Storage
User->>Helm: helm install myapp ./chart
Helm->>Helm: Render templates with values
Helm->>K8s: Create resources
K8s-->>Helm: Resources created
Helm->>Storage: Store release info
Storage-->>Helm: Release saved
Helm-->>User: Installation complete
Key Components:
Helm Client: Command-line tool that developers and operators use to:
- Create and package charts
- Install and upgrade releases
- Manage repositories
- Query release history
Charts: Directories containing files that describe Kubernetes resources:
- Templates (Kubernetes manifests with templating)
- Values (configuration parameters)
- Chart metadata
- Dependencies
- Documentation
Releases: Instances of charts running in a cluster with specific configurations. Each installation creates a new release with its own version history.
Repositories: HTTP servers that host chart packages, enabling distribution and discovery.
Installing Helm
Installation is straightforward across platforms:
Linux:
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Verify installation
helm version
macOS:
brew install helm
# Verify installation
helm version
Windows (PowerShell):
choco install kubernetes-helm
# Verify installation
helm version
From Binary:
# Download the desired version from https://github.com/helm/helm/releases
wget https://get.helm.sh/helm-v3.12.0-linux-amd64.tar.gz
tar -zxvf helm-v3.12.0-linux-amd64.tar.gz
sudo mv linux-amd64/helm /usr/local/bin/helm
# Verify installation
helm version
Basic Helm Commands
The Helm CLI provides intuitive commands for common operations:
Installing a Chart:
# Install from a local chart directory
helm install myapp ./my-chart
# Install from a repository
helm install myapp bitnami/nginx
# Install with custom values
helm install myapp ./my-chart -f custom-values.yaml
# Install with inline value overrides
helm install myapp ./my-chart --set image.tag=v2.0.0
Listing Releases:
# List all releases in current namespace
helm list
# List releases in all namespaces
helm list --all-namespaces
# List releases matching a filter
helm list --filter '^myapp'
Getting Release Information:
# Show release status
helm status myapp
# Show values used in a release
helm get values myapp
# Show all computed values (including defaults)
helm get values myapp --all
# Show generated manifest
helm get manifest myapp
Upgrading a Release:
# Upgrade with new chart version
helm upgrade myapp ./my-chart
# Upgrade with new values
helm upgrade myapp ./my-chart -f production-values.yaml
# Force resource updates
helm upgrade myapp ./my-chart --force
# Perform dry-run to preview changes
helm upgrade myapp ./my-chart --dry-run --debug
Rolling Back:
# List release history
helm history myapp
# Rollback to previous version
helm rollback myapp
# Rollback to specific revision
helm rollback myapp 3
Uninstalling:
# Uninstall a release
helm uninstall myapp
# Uninstall but keep release history
helm uninstall myapp --keep-history
Chart Structure
A Helm chart follows a standard directory structure:
my-chart/
├── Chart.yaml # Chart metadata
├── values.yaml # Default configuration values
├── charts/ # Dependent charts
├── templates/ # Kubernetes manifest templates
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── _helpers.tpl # Template helpers
│ └── NOTES.txt # Post-install notes
└── README.md # Chart documentation
Chart.yaml - Chart Metadata:
apiVersion: v2
name: my-application
description: A Helm chart for my application
type: application
version: 1.0.0 # Chart version
appVersion: "2.1.3" # Application version
keywords:
- web
- api
maintainers:
- name: Platform Team
email: platform@company.com
dependencies:
- name: postgresql
version: 12.x.x
repository: https://charts.bitnami.com/bitnami
values.yaml - Configuration:
replicaCount: 3
image:
repository: myapp/api
tag: v2.1.3
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
targetPort: 8080
ingress:
enabled: true
className: nginx
hosts:
- host: api.example.com
paths:
- path: /
pathType: Prefix
resources:
limits:
cpu: 1000m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 80
templates/deployment.yaml - Templated Manifest:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "my-chart.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "my-chart.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
resources:
{{- toYaml .Values.resources | nindent 10 }}
This template demonstrates several Helm features:
- Variable substitution:
{{ .Values.replicaCount }} - Conditional logic:
{{- if not .Values.autoscaling.enabled }} - Template functions:
include,nindent,toYaml - Default values:
{{ .Values.image.tag | default .Chart.AppVersion }}
Working with Helm Repositories
Helm repositories enable chart sharing and distribution:
Adding Repositories:
# Add the Bitnami repository
helm repo add bitnami https://charts.bitnami.com/bitnami
# Add the Prometheus community repository
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
# Add a private repository with authentication
helm repo add mycompany https://charts.company.com \
--username admin \
--password secretpass
Managing Repositories:
# List configured repositories
helm repo list
# Update repository indexes
helm repo update
# Remove a repository
helm repo remove bitnami
Searching for Charts:
# Search all configured repositories
helm search repo nginx
# Search the Artifact Hub
helm search hub nginx
# Show chart information
helm show chart bitnami/nginx
# Show chart values
helm show values bitnami/nginx
# Show all chart information
helm show all bitnami/nginx
Practical Example - Deploying a Web Application
Deploy a complete web application with database dependency:
Step 1: Create Chart Structure
helm create webapp
cd webapp
Step 2: Configure values.yaml
replicaCount: 2
image:
repository: company/webapp
tag: "1.0.0"
pullPolicy: IfNotPresent
service:
type: LoadBalancer
port: 80
targetPort: 3000
env:
- name: NODE_ENV
value: production
- name: DATABASE_HOST
value: webapp-postgresql
- name: DATABASE_PORT
value: "5432"
postgresql:
enabled: true
auth:
database: webappdb
username: webappuser
password: secretpassword
primary:
persistence:
enabled: true
size: 10Gi
Step 3: Add Database Dependency in Chart.yaml
apiVersion: v2
name: webapp
description: Complete web application with database
type: application
version: 1.0.0
appVersion: "1.0.0"
dependencies:
- name: postgresql
version: 12.x.x
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
Step 4: Update Dependencies
helm dependency update
Step 5: Install the Application
# Install with default values
helm install webapp ./webapp
# Install with custom values
helm install webapp ./webapp -f production-values.yaml
# Install in specific namespace
helm install webapp ./webapp -n production --create-namespace
Step 6: Verify Deployment
# Check release status
helm status webapp
# Watch pods starting
kubectl get pods -w
# Get service endpoint
kubectl get svc webapp
Step 7: Upgrade with New Configuration
# Update values.yaml with new replica count
# replicaCount: 5
# Apply upgrade
helm upgrade webapp ./webapp
# Verify upgrade
helm history webapp
Step 8: Rollback If Needed
# Check what changed
helm diff revision webapp 1 2
# Rollback to previous version
helm rollback webapp
# Verify rollback
helm status webapp
Release Management
Helm provides powerful release lifecycle management:
stateDiagram-v2
[*] --> Deployed: helm install
Deployed --> Upgraded: helm upgrade
Upgraded --> Upgraded: helm upgrade
Upgraded --> RolledBack: helm rollback
RolledBack --> Deployed
Deployed --> Uninstalled: helm uninstall
Upgraded --> Uninstalled: helm uninstall
RolledBack --> Uninstalled: helm uninstall
Uninstalled --> [*]
Viewing Release History:
# Show all revisions
helm history webapp
# Output:
# REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
# 1 Mon Oct 23 10:00:00 2023 superseded webapp-1.0.0 1.0.0 Install complete
# 2 Mon Oct 23 14:30:00 2023 deployed webapp-1.1.0 1.1.0 Upgrade complete
Release Testing:
# Run chart tests
helm test webapp
# Tests are defined in templates/tests/ directory
# Example: templates/tests/test-connection.yaml
Helm Hooks
Hooks allow executing actions at specific points in the release lifecycle:
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "my-chart.fullname" . }}-migration
annotations:
"helm.sh/hook": pre-upgrade
"helm.sh/hook-weight": "1"
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
spec:
containers:
- name: migration
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
command: ["npm", "run", "migrate"]
restartPolicy: Never
Available Hooks:
pre-install: Before resources are createdpost-install: After all resources are loadedpre-upgrade: Before upgradepost-upgrade: After upgradepre-rollback: Before rollbackpost-rollback: After rollbackpre-delete: Before deletionpost-delete: After deletiontest: Whenhelm testruns
Benefits of Using Helm
Consistency: Deploy applications the same way across environments using different value files.
Reusability: Package once, deploy anywhere with environment-specific configuration.
Versioning: Track what was deployed when, and easily rollback if issues arise.
Dependency Management: Handle complex multi-tier applications with automatic dependency resolution.
Template Power: Generate complex manifests dynamically based on simple configuration.
Community Ecosystem: Leverage thousands of pre-built charts for common applications.
When to Use Helm
Ideal For:
- Deploying complex applications with multiple Kubernetes resources
- Managing multiple environments (dev, staging, production) with different configurations
- Applications with dependencies (e.g., web app + database + cache)
- Packaging applications for distribution to other teams or customers
- Standardizing deployment processes across the organization
Consider Alternatives When:
- Deploying simple single-resource applications
- GitOps workflows where plain manifests are preferred (though Helm + ArgoCD works well)
- Teams prefer simpler tools like Kustomize for pure YAML manipulation
- Templating logic becomes too complex to maintain
Common Pitfalls
Over-Templating: Creating overly complex templates with excessive logic makes charts hard to understand and maintain. Keep templates simple and readable.
Ignoring Dependencies: Forgetting to run helm dependency update after modifying Chart.yaml leads to outdated or missing dependency charts.
Not Using Dry-Run: Deploying without --dry-run testing can result in unexpected changes. Always preview changes before applying.
Poor Value Structure: Flat, disorganized values files become unwieldy. Use nested structures that mirror the application architecture.
Skipping Documentation: Charts without README files or comments force users to reverse-engineer behavior. Document values and expected usage.
Version Confusion: Mixing up chart versions and application versions causes deployment issues. Maintain clear versioning for both.
Key Takeaways
- Helm packages Kubernetes applications into charts - reusable, versioned bundles of manifests
- Helm 3 uses a client-only architecture that communicates directly with the Kubernetes API
- Charts consist of templates (dynamic manifests), values (configuration), and metadata (Chart.yaml)
- Templates use Go templating syntax to generate manifests dynamically based on provided values
- Releases are instances of charts running in a cluster with their own version history and configurations
- Helm enables easy upgrades and rollbacks with
helm upgradeandhelm rollbackcommands - Repositories host and distribute charts, enabling sharing across teams and organizations
- Dependencies allow charts to include other charts, handling complex multi-tier applications automatically
- Hooks execute jobs at specific lifecycle points (pre-install, post-upgrade, etc.) for tasks like migrations
- Use
--dry-runand--debugflags to preview changes before applying them to clusters - Keep templates simple and readable - avoid over-engineering with excessive conditional logic
- Different value files enable environment-specific configurations (dev, staging, production) from a single chart
- Helm complements GitOps workflows when paired with tools like ArgoCD for continuous delivery
- Chart versioning is separate from application versioning - increment both appropriately