Helm Charts: The Complete Guide to Kubernetes Package Management
📅 Published: August 2026
⏱️ Estimated Reading Time: 15 minutes
🏷️ Tags: Helm, Kubernetes, Package Management, DevOps, Charts
Introduction: What is Helm?
Helm is the package manager for Kubernetes. Think of it as apt, yum, or Homebrew for Kubernetes applications. It simplifies the process of defining, installing, and upgrading complex Kubernetes applications.
Helm solves a fundamental problem: Deploying a modern application to Kubernetes might require 10-20 different YAML files (Deployment, Service, Ingress, ConfigMap, Secret, PersistentVolumeClaim, etc.). Managing and customizing all of these for different environments (dev, staging, prod) becomes a maintenance nightmare.
Helm introduces two key concepts:
Charts: A packaged collection of Kubernetes resources (like a package)
Releases: A running instance of a chart (like an installed package)
Why Helm is essential:
Package management: Reuse and share Kubernetes configurations
Templating: Parameterize YAML files for different environments
Rollbacks: Roll back to previous versions easily
Dependency management: Manage dependencies between charts
Release management: Track and upgrade releases
Part 1: Helm Architecture
Core Components
┌─────────────────────────────────────────────────────────────────┐
│ Helm Client (CLI) │
│ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ helm │ │ Chart │ │ Release │ │
│ │ install │───▶│ Repo │───▶│ Manager │ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ │
└───────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Tiller (Helm v2 - Deprecated) │
│ Kubernetes API │
└───────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Kubernetes API │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Secrets │ │ Config │ │ Release │ │
│ │ (state) │ │ Maps │ │ History │ │
│ └───────────┘ └───────────┘ └───────────┘ │
└─────────────────────────────────────────────────────────────────┘Helm v2 vs Helm v3
| Aspect | Helm v2 | Helm v3 |
|---|---|---|
| Server component | Tiller (in-cluster) | None (client-only) |
| Security | Tiller has cluster-wide access | Uses standard Kubernetes RBAC |
| Release storage | ConfigMaps in cluster | Secrets in cluster |
| CRD support | Limited | Full support |
| OCI registry support | No | Yes |
| JSON schema validation | No | Yes |
Part 2: Installing Helm
macOS
brew install helmLinux (via script)
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh
Add a Chart Repository
# Add stable repo helm repo add stable https://charts.helm.sh/stable # Add bitnami repo (popular for production) helm repo add bitnami https://charts.bitnami.com/bitnami # Update repos helm repo update # List repos helm repo list
Part 3: Basic Helm Commands
# Find a chart helm search hub nginx # Search Artifact Hub helm search repo nginx # Search local repos # Install a chart helm install my-release bitnami/nginx # List releases helm list helm list -a # All releases helm list -n my-namespace # Specific namespace # Upgrade a release helm upgrade my-release bitnami/nginx # Rollback a release helm rollback my-release 1 # Rollback to revision 1 # Uninstall a release helm uninstall my-release # Show chart details helm show chart bitnami/nginx helm show values bitnami/nginx helm show readme bitnami/nginx # Get release status helm status my-release
Part 4: Creating Your First Chart
Chart Structure
myapp/ ├── Chart.yaml # Chart metadata ├── values.yaml # Default values ├── templates/ # Kubernetes YAML templates │ ├── NOTES.txt # Post-install notes │ ├── _helpers.tpl # Helper functions │ ├── deployment.yaml │ ├── service.yaml │ ├── ingress.yaml │ ├── configmap.yaml │ └── secrets.yaml └── charts/ # Dependencies
Creating a Chart
# Create a new chart helm create myapp # Chart structure created cd myapp ls -la # Chart.yaml templates/ values.yaml
Chart.yaml
apiVersion: v2 name: myapp description: My application Helm chart type: application version: 0.1.0 appVersion: "1.0.0" maintainers: - name: Developer Name email: dev@example.com keywords: - web - app home: https://example.com sources: - https://github.com/example/myapp dependencies: - name: postgresql version: 12.1.2 repository: https://charts.bitnami.com/bitnami condition: postgresql.enabled
values.yaml
# Default configuration replicaCount: 3 image: repository: nginx tag: "1.21" pullPolicy: IfNotPresent service: type: ClusterIP port: 80 ingress: enabled: false className: "" annotations: {} hosts: - host: chart-example.local paths: - path: / pathType: Prefix resources: limits: cpu: 500m memory: 512Mi requests: cpu: 250m memory: 256Mi autoscaling: enabled: false minReplicas: 1 maxReplicas: 10 env: - name: ENVIRONMENT value: production config: database: host: postgresql port: 5432
Part 5: Templates and Templating
Template Structure (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 }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - containerPort: {{ .Values.service.port }} env: {{- toYaml .Values.env | nindent 12 }} resources: {{- toYaml .Values.resources | nindent 12 }}
Helper Template (_helpers.tpl)
{{- define "myapp.fullname" -}} {{- if .Values.fullnameOverride -}} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} {{- else -}} {{- $name := default .Chart.Name .Values.nameOverride -}} {{- if contains $name .Release.Name -}} {{- .Release.Name | trunc 63 | trimSuffix "-" -}} {{- else -}} {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} {{- end -}} {{- end -}} {{- end -}} {{- define "myapp.labels" -}} helm.sh/chart: {{ include "myapp.name" . }}-{{ .Chart.Version }} {{ include "myapp.selectorLabels" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}}
Built-in Objects
| Object | Description |
|---|---|
.Values | Values from values.yaml and user input |
.Release | Release metadata (Name, Namespace, Revision) |
.Chart | Chart metadata (Name, Version, AppVersion) |
.Files | Access files in the chart |
.Capabilities | Kubernetes cluster capabilities |
.Template | Template execution information |
Template Functions
# String functions {{ .Values.name | default "default-name" }} {{ .Values.name | quote }} {{ .Values.name | lower }} {{ .Values.name | upper }} {{ .Values.name | title }} # List functions {{ range .Values.items }} - name: {{ . }} {{ end }} # Conditional statements {{- if .Values.ingress.enabled }} ingress: enabled: true {{- end }} # Loop with range {{- range .Values.env }} - name: {{ .name }} value: {{ .value }} {{- end }} # Pipeline {{ .Values.name | default "default" | quote }} # Convert to YAML {{- toYaml .Values.config | nindent 4 }}
Part 6: Managing Values
Values Precedence (Highest to Lowest)
Command line
--setvaluesValues from
-ffileValues in
values.yaml(chart defaults)
Setting Values
# Install with values file helm install my-release ./myapp -f prod-values.yaml # Set individual values helm install my-release ./myapp --set image.tag=1.22 --set replicaCount=5 # Set nested values helm install my-release ./myapp --set config.database.host=db.example.com # Multiple --set flags helm install my-release ./myapp \ --set image.tag=1.22 \ --set replicaCount=5 \ --set service.type=NodePort
prod-values.yaml Example
# Environment-specific values replicaCount: 5 image: repository: myapp tag: "2.0.0" service: type: LoadBalancer port: 80 ingress: enabled: true hosts: - host: app.example.com resources: limits: cpu: 1000m memory: 2Gi autoscaling: enabled: true minReplicas: 3 maxReplicas: 10
Part 7: Installing and Upgrading
Install a Chart
# Install from repo helm install my-nginx bitnami/nginx # Install local chart helm install myapp ./myapp # Install with custom values helm install myapp ./myapp -f values-prod.yaml # Install in a specific namespace helm install myapp ./myapp -n production --create-namespace # Install with release name override helm install myapp ./myapp --set nameOverride=myapp-custom
Upgrade a Release
# Upgrade to new version helm upgrade myapp ./myapp # Upgrade with new values helm upgrade myapp ./myapp -f values-prod.yaml # Upgrade with --set helm upgrade myapp ./myapp --set image.tag=2.1.0 # Install if not exists helm upgrade --install myapp ./myapp
Rollback
# List revisions helm history myapp # Rollback to previous version helm rollback myapp 1 # Rollback to specific revision helm rollback myapp 2
Part 8: Managing Dependencies
Adding Dependencies
# Chart.yaml dependencies: - name: postgresql version: 12.1.2 repository: https://charts.bitnami.com/bitnami condition: postgresql.enabled - name: redis version: 17.3.1 repository: https://charts.bitnami.com/bitnami condition: redis.enabled
# Update dependencies helm dependency update # Build dependencies helm dependency build
Values for Dependencies
# values.yaml postgresql: enabled: true auth: postgresPassword: "postgres" database: "myapp" primary: persistence: size: 10Gi redis: enabled: true architecture: standalone auth: enabled: true password: "redis"
Part 9: Testing Charts
Helm Test
# templates/tests/test-connection.yaml apiVersion: v1 kind: Pod metadata: name: "{{ include "myapp.fullname" . }}-test-connection" labels: {{- include "myapp.labels" . | nindent 4 }} annotations: "helm.sh/hook": test spec: containers: - name: wget image: busybox command: ['wget'] args: ['{{ include "myapp.fullname" . }}:{{ .Values.service.port }}'] restartPolicy: Never
# Run tests helm test myapp # Run tests with logs helm test myapp --logs # Run tests and cleanup helm test myapp --cleanup
Linting Charts
# Lint chart helm lint ./myapp # Lint with strict mode helm lint ./myapp --strict
Part 10: Chart Repositories
Creating a Repository
# Package chart helm package ./myapp # Create index.yaml helm repo index --url https://charts.example.com . # Upload to web server # Add to your web server (S3, GitHub Pages, etc.)
Using a Repository
# Add repo helm repo add myrepo https://charts.example.com # Update repos helm repo update # Search repo helm search repo myrepo
OCI Registry (Helm v3)
# Login to OCI registry helm registry login registry.example.com # Push chart to OCI helm push myapp-0.1.0.tgz oci://registry.example.com/charts # Install from OCI helm install myapp oci://registry.example.com/charts/myapp
Part 11: Advanced Templates
Conditionals
{{- if .Values.ingress.enabled }} apiVersion: networking.k8s.io/v1 kind: Ingress ... {{- end }}
Loops
{{- range .Values.env }} - name: {{ .name }} value: {{ .value }} {{- end }}
With Statement
{{- with .Values.config }} database: host: {{ .database.host }} port: {{ .database.port }} {{- end }}
Include Function
{{- include "myapp.fullname" . -}}
Required Values
{{- required "A valid .Values.image.repository is required!" .Values.image.repository }}
Helm Commands Cheat Sheet
# Repo Management helm repo add <name> <url> helm repo list helm repo update helm repo remove <name> # Chart Management helm create <name> helm package <chart> helm lint <chart> # Install/Upgrade helm install <name> <chart> helm upgrade <name> <chart> helm upgrade --install <name> <chart> helm rollback <name> <revision> helm uninstall <name> # Status helm list helm history <name> helm status <name> helm get <name> helm get values <name> helm get manifest <name> # Testing helm test <name> helm template <name> <chart>
Summary
| Concept | Description |
|---|---|
| Chart | Package of Kubernetes resources |
| Release | Running instance of a chart |
| Repository | Collection of charts |
| Values | Configuration for a chart |
| Templates | Kubernetes YAML with Go templating |
| Dependencies | Charts that depend on other charts |
Helm is the standard for packaging and deploying applications on Kubernetes. It makes complex deployments simple, repeatable, and maintainable.
Learn More
Practice Helm with hands-on exercises in our interactive labs:
https://devops.trainwithsky.com
Comments
Post a Comment