Helm Chart Guide¶
Package and deploy USL applications using Helm, the Kubernetes package manager.
Overview¶
Helm charts provide: - Templating: Reusable configurations across environments - Versioning: Track and rollback deployments - Dependencies: Manage related services - Values: Environment-specific configuration
Generate Helm Chart¶
Generated structure:
helm-chart/
├── Chart.yaml # Chart metadata
├── values.yaml # Default values
├── .helmignore # Files to ignore
├── README.md # Installation guide
└── templates/
├── deployment.yaml
├── service.yaml
├── ingress.yaml
├── configmap.yaml
├── hpa.yaml
├── servicemonitor.yaml
├── _helpers.tpl # Template helpers
└── NOTES.txt # Post-install notes
Chart.yaml¶
Metadata about the chart:
apiVersion: v2
name: my-app
description: A Helm chart for my-app generated by USL Compiler
type: application
version: 0.1.0
appVersion: "1.0.0"
keywords:
- usl
- microservice
- api
maintainers:
- name: Your Team
email: team@example.com
values.yaml¶
Default configuration values:
replicaCount: 3
image:
repository: my-app
pullPolicy: IfNotPresent
tag: "latest"
service:
type: ClusterIP
port: 80
targetPort: 8000
ingress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
hosts:
- host: my-app.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: my-app-tls
hosts:
- my-app.example.com
resources:
limits:
cpu: 2000m
memory: 2Gi
requests:
cpu: 1000m
memory: 512Mi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
monitoring:
enabled: true
serviceMonitor:
enabled: true
interval: 30s
Installation¶
Install from Local Chart¶
Install with Custom Values¶
helm install my-release ./helm-chart \
--values production-values.yaml \
--namespace production \
--create-namespace
Install with CLI Overrides¶
helm install my-release ./helm-chart \
--set replicaCount=5 \
--set image.tag=v1.2.3 \
--set ingress.hosts[0].host=api.example.com \
--namespace production
Environment-Specific Values¶
development-values.yaml¶
replicaCount: 1
image:
tag: "dev"
pullPolicy: Always
ingress:
enabled: true
hosts:
- host: my-app-dev.example.com
tls: []
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
autoscaling:
enabled: false
production-values.yaml¶
replicaCount: 5
image:
tag: "v1.2.3"
pullPolicy: IfNotPresent
ingress:
enabled: true
annotations:
nginx.ingress.kubernetes.io/rate-limit: "1000"
hosts:
- host: api.example.com
tls:
- secretName: api-tls
hosts:
- api.example.com
resources:
limits:
cpu: 4000m
memory: 4Gi
requests:
cpu: 2000m
memory: 2Gi
autoscaling:
enabled: true
minReplicas: 5
maxReplicas: 20
targetCPUUtilizationPercentage: 60
Common Operations¶
List Releases¶
Upgrade Release¶
Rollback Release¶
# List revision history
helm history my-release -n production
# Rollback to previous version
helm rollback my-release -n production
# Rollback to specific revision
helm rollback my-release 3 -n production
Uninstall Release¶
Test Release¶
Template Testing¶
Dry Run¶
Preview generated manifests:
Template Rendering¶
Render templates locally:
helm template my-release ./helm-chart \
--values production-values.yaml \
--namespace production \
> rendered.yaml
Lint Chart¶
Validate chart structure:
Template Functions¶
Helpers (_helpers.tpl)¶
Common template patterns:
{{/* Generate full name */}}
{{- define "chart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{/* Common labels */}}
{{- define "chart.labels" -}}
helm.sh/chart: {{ include "chart.chart" . }}
{{ include "chart.selectorLabels" . }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
Using in Templates¶
metadata:
name: {{ include "chart.fullname" . }}
labels:
{{- include "chart.labels" . | nindent 4 }}
Advanced Features¶
Conditional Resources¶
{{- if .Values.monitoring.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "chart.fullname" . }}
spec:
selector:
matchLabels:
{{- include "chart.selectorLabels" . | nindent 6 }}
{{- end }}
Loops¶
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "chart.fullname" $ }}
{{- end }}
{{- end }}
Dependencies¶
Add to Chart.yaml:
dependencies:
- name: postgresql
version: "12.1.2"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
- name: redis
version: "17.3.7"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled
Install dependencies:
Hooks¶
Lifecycle hooks for database migrations, tests:
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "chart.fullname" . }}-migration
annotations:
"helm.sh/hook": pre-upgrade,pre-install
"helm.sh/hook-weight": "-1"
"helm.sh/hook-delete-policy": before-hook-creation
spec:
template:
spec:
containers:
- name: migration
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
command: ["python", "migrate.py"]
restartPolicy: Never
Packaging & Distribution¶
Package Chart¶
Create Chart Repository¶
# Create index
helm repo index . --url https://charts.example.com
# Serve via HTTP
helm serve --address localhost:8879 --url http://localhost:8879/charts/
OCI Registry¶
Push to OCI-compatible registry:
Best Practices¶
1. Use Values for Everything¶
❌ Bad: Hardcoded values
✅ Good: Templated values
2. Provide Sensible Defaults¶
3. Document Values¶
# Number of replicas
replicaCount: 3
# Image configuration
image:
# Image repository
repository: my-app
# Image pull policy
pullPolicy: IfNotPresent
4. Use Semantic Versioning¶
5. Include NOTES.txt¶
Provide post-install instructions:
1. Get the application URL by running:
{{- if .Values.ingress.enabled }}
https://{{ .Values.ingress.hosts[0].host }}
{{- else }}
kubectl port-forward svc/{{ include "chart.fullname" . }} 8080:80
{{- end }}
2. Check the deployment status:
kubectl get pods -l app.kubernetes.io/name={{ include "chart.name" . }}
Troubleshooting¶
Debug Template Rendering¶
Check Values¶
Check Manifest¶
Common Errors¶
"template: ... can't evaluate field" - Missing value in values.yaml - Fix: Add default or conditional check
"release ... failed: rendered manifests contain a resource that already exists" - Resource name conflict - Fix: Use helm upgrade instead of install
"Validation failed: ... Invalid value" - Invalid Kubernetes resource - Fix: Check Kubernetes API version and schema
CI/CD Integration¶
GitHub Actions¶
name: Deploy with Helm
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Helm
uses: azure/setup-helm@v3
with:
version: 'v3.12.0'
- name: Deploy
run: |
helm upgrade --install my-app ./helm-chart \
--values production-values.yaml \
--set image.tag=${{ github.sha }} \
--namespace production \
--wait
Next Steps¶
- Kubernetes Guide - Direct K8s deployment
- Secret Management - Secure secret handling
- Cloud Providers - Cloud-specific features
- Monitoring - Observability setup