Skip to content

Helm_charts

Helm is the Kubernetes package manager that helps define, install, and upgrade complex Kubernetes applications. Charts are packages of pre-configured Kubernetes resources.

  • Package management: Bundle Kubernetes manifests into a single deployable unit
  • Templating: Use templates with configurable values
  • Versioning: Track release history and rollback
  • Reusability: Share charts via repositories
  • Simplified deployment: One command to install entire applications
┌─────────────────────────────────────────────────────────────────┐
│ Helm Architecture │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ helm CLI │────▶│ Tiller │────▶│ K8s API │ │
│ │ (Client) │ │ (Server) │ │ Server │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Chart Structure │ │
│ │ mychart/ │ │
│ │ ├── Chart.yaml # Chart metadata │ │
│ │ ├── values.yaml # Default config values │ │
│ │ ├── values.schema.json # Values validation schema │ │
│ │ ├── templates/ # Kubernetes manifests │ │
│ │ │ ├── deployment.yaml │ │ │
│ │ │ ├── service.yaml │ │ │
│ │ │ └── _helpers.tpl │ # Template helpers │ │
│ │ └── charts/ # Chart dependencies │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

Note: Helm 3 removed Tiller and uses a purely client-side architecture.

Terminal window
# Using script
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Using package managers
# macOS
brew install helm
# Linux
sudo apt-get install helm
# Windows
choco install kubernetes-helm

Verify installation:

Terminal window
helm version
helm repo list
Terminal window
# Create new chart
helm create mychart
# Chart structure
mychart/
├── Chart.yaml # Chart metadata
├── values.yaml # Default values
├── values.schema.json # JSON schema for values validation
├── charts/ # Dependencies
├── templates/ # Manifest templates
├── deployment.yaml
├── _helpers.tpl # Template helper functions
├── service.yaml
├── serviceaccount.yaml
└── NOTES.txt # Post-install instructions
└── tests/ # Test manifests
└── test-connection.yaml
apiVersion: v2
name: mychart
description: A Helm chart for Kubernetes
type: application
version: 1.0.0
appVersion: "1.0.0"
kubeVersion: ">=1.20.0"
keywords:
- myapp
- web
home: https://myapp.example.com
sources:
- https://github.com/example/myapp
maintainers:
- name: John Doe
email: john@example.com
dependencies: []
annotations:
category: WebApplication
replicaCount: 2
image:
repository: myapp/myapp
pullPolicy: IfNotPresent
tag: "1.0.0"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
create: true
annotations: {}
name: ""
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: myapp.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: myapp-tls
hosts:
- myapp.example.com
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "mychart.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "mychart.serviceAccountName" . }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{/*
Expand the name of the chart.
*/}}
{{- define "mychart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "mychart.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 }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "mychart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "mychart.labels" -}}
helm.sh/chart: {{ include "mychart.chart" . }}
{{ include "mychart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "mychart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "mychart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "mychart.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- include "mychart.fullname" . }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
Terminal window
# Install chart from current directory
helm install myrelease ./mychart
# Install with custom values
helm install myrelease ./mychart --set replicaCount=3
# Install with values file
helm install myrelease ./mychart -f myvalues.yaml
# Dry run (see what would be installed)
helm install myrelease ./mychart --dry-run
# Install with all values shown
helm install myrelease ./mychart --dry-run --debug
Terminal window
# List releases
helm list
helm list --all
# Upgrade release
helm upgrade myrelease ./mychart
# Upgrade with new values
helm upgrade myrelease ./mychart --set replicaCount=5
# Rollback to previous release
helm rollback myrelease
# Rollback to specific revision
helm rollback myrelease 2
# Uninstall release
helm uninstall myrelease
# Get release status
helm status myrelease
# Get release history
helm history myrelease
Terminal window
# Add repository
helm repo add bitnami https://charts.bitnami.com/bitnami
# Update repository
helm repo update
# Search charts
helm search repo nginx
helm search repo bitnami
# Install from repository
helm install mynginx bitnami/nginx
# Remove repository
helm repo remove bitnami
apiVersion: v2
name: mychart
version: 1.0.0
dependencies:
- name: postgresql
version: "11.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
- name: redis
version: "17.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled
postgresql:
enabled: true
auth:
username: myapp
password: secretpassword
database: myappdb
redis:
enabled: true
auth:
password: redispassword

Then run:

Terminal window
# Download dependencies
helm dependency build ./mychart
# Update dependencies
helm dependency update ./mychart
Terminal window
# Render templates locally
helm template myrelease ./mychart
# Render with values
helm template myrelease ./mychart --set replicaCount=5
# Render with namespace
helm template myrelease ./mychart --namespace mynamespace
test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "mychart.fullname" . }}-test-connection"
labels:
{{- include "mychart.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "mychart.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

Run tests:

Terminal window
# Run tests
helm test myrelease
# Run tests with verbose output
helm test myrelease --logs
metadata:
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "1"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded

Available hooks:

  • pre-install: Run before any resources are installed
  • post-install: Run after all resources are installed
  • pre-upgrade: Run before upgrade
  • post-upgrade: Run after upgrade
  • pre-rollback: Run before rollback
  • post-rollback: Run after rollback
  • pre-uninstall: Run before uninstall
  • post-uninstall: Run after uninstall
  1. Use semantic versioning: Follow semver for chart versions
  2. Validate values: Use values.schema.json
  3. Template everything: Avoid duplication with templates
  4. Use _helpers.tpl: Share common template logic
  5. Write tests: Include Helm tests for validation
  6. Document values: Add comments in values.yaml
  7. Version control: Keep charts in Git
  8. Use CI/CD: Automate testing and publishing

Helm is essential for:

  • Package management: Distribute Kubernetes applications
  • Version control: Track and rollback releases
  • Templating: Customize deployments
  • Reusability: Share and reuse charts
  • Production-ready: Handle complex deployments

Key concepts:

  • Chart: Package definition
  • Release: Deployed instance
  • Repository: Chart storage
  • Template: Manifest generation
  • Values: Configuration
  • Hooks: Lifecycle management