Helm is the package manager for Kubernetes, simplifying application deployment and management through reusable packages called charts. It enables you to define, install, and upgrade complex Kubernetes applications.
Key Benefits:
- Package Management: Bundle Kubernetes resources into charts
- Template System: Parameterize deployments with values
- Version Control: Manage application versions
- Dependency Management: Handle chart dependencies
- Rollback: Easy rollback to previous versions
- Release Management: Track deployed releases
- Large Ecosystem: 10,000+ charts available
- Chart: Package of Kubernetes resources
- Release: Installed chart instance
- Values: Configuration parameters
- Templates: Kubernetes manifests with variables
- Repository: Chart storage location
mychart/
├── Chart.yaml # Chart metadata
├── values.yaml # Default values
├── charts/ # Chart dependencies
├── templates/ # Template files
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── secret.yaml
│ ├── _helpers.tpl # Helper templates
│ └── NOTES.txt # Installation notes
└── templates/tests/ # Test files
└── test-connection.yaml
apiVersion: v2
name: myapp
description: A Helm chart for my application
type: application
version: 1.0.0
appVersion: "1.0.0"
keywords:
- web
- application
home: https://example.com
sources:
- https://github.com/user/repo
maintainers:
- name: DevOps Team
email: devops@example.com
dependencies:
- name: postgresql
version: "12.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled# Default values
replicaCount: 3
image:
repository: nginx
pullPolicy: IfNotPresent
tag: "1.21"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
create: true
annotations: {}
name: ""
podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 80
targetPort: 80
ingress:
enabled: false
className: "nginx"
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
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: false
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}
# PostgreSQL dependency
postgresql:
enabled: true
auth:
postgresPassword: "changeme"
database: "myapp"apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
labels:
{{- include "myapp.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "myapp.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "myapp.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "myapp.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ include "myapp.fullname" . }}-postgresql
key: postgresql-password
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}apiVersion: v1
kind: Service
metadata:
name: {{ include "myapp.fullname" . }}
labels:
{{- include "myapp.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "myapp.selectorLabels" . | nindent 4 }}{{/*
Expand the name of the chart.
*/}}
{{- define "myapp.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- 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 }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "myapp.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "myapp.labels" -}}
helm.sh/chart: {{ include "myapp.chart" . }}
{{ include "myapp.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "myapp.selectorLabels" -}}
app.kubernetes.io/name: {{ include "myapp.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "myapp.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "myapp.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}# Create new chart
helm create mychart
# Package chart
helm package mychart
# Install chart
helm install myapp ./mychart
helm install myapp ./mychart -n production
helm install myapp ./mychart --set replicaCount=5
helm install myapp ./mychart -f values-production.yaml
# Upgrade release
helm upgrade myapp ./mychart
helm upgrade myapp ./mychart --set image.tag=v2.0.0
helm upgrade myapp ./mychart --reuse-values
# Rollback
helm rollback myapp
helm rollback myapp 2 # To revision 2
# Uninstall
helm uninstall myapp
helm uninstall myapp -n production# List releases
helm list
helm list -A # All namespaces
helm list --all # Including failed
# Get release info
helm get all myapp
helm get values myapp
helm get manifest myapp
helm get notes myapp
helm get hooks myapp
# History
helm history myapp# Add repository
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add stable https://charts.helm.sh/stable
# List repositories
helm repo list
# Update repositories
helm repo update
# Search charts
helm search repo nginx
helm search repo bitnami/nginx
# Remove repository
helm repo remove bitnami# Template (dry-run)
helm template myapp ./mychart
helm template myapp ./mychart --values values.yaml
helm template myapp ./mychart --debug
# Lint chart
helm lint ./mychart
# Test chart
helm test myapp# Update dependencies
helm dependency update ./mychart
# Build dependencies
helm dependency build ./mychart
# List dependencies
helm dependency list ./mychartChart.yaml:
dependencies:
- name: postgresql
version: "12.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
tags:
- databasevalues.yaml:
postgresql:
enabled: true
auth:
postgresPassword: "changeme"# Pre-install hook
apiVersion: batch/v1
kind: Job
metadata:
name: pre-install-job
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation
spec:
template:
spec:
containers:
- name: pre-install
image: busybox
command: ['sh', '-c', 'echo Pre-install hook']
restartPolicy: Nevertemplates/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# Use semantic versioning
version: 1.0.0
appVersion: "1.0.0"# Don't hardcode values
# Use .Values for all configuration
replicas: {{ .Values.replicaCount }}# Chart.yaml
description: Clear description
home: Project homepage
sources: Source code location
maintainers: Maintainer informationhelm lint ./mychart
helm template myapp ./mychart --debug
helm install myapp ./mychart --dry-run --debug# _helpers.tpl for reusable templates
{{- define "myapp.labels" -}}
# ...
{{- end }}- Create Helm charts
- Use templates and values
- Manage chart dependencies
- Implement hooks
- Create chart tests
- Publish charts to repository
- Use Helm with CI/CD
- Manage releases
- Rollback releases
- Optimize chart structure
Next Steps:
- Learn Kubernetes Operations
- Explore Argo CD for GitOps
- Master Terraform for infrastructure
Remember: Helm simplifies Kubernetes deployments. Use values for configuration, test charts thoroughly, and version properly. Start with simple charts and gradually add complexity.