Helm Hooks
A comprehensive guide to Helm hooks covering pre-install, post-install, pre-upgrade, post-upgrade hooks, and best practices for lifecycle management in Helm charts.
Helm hooks are special resources that run at specific points during the lifecycle of a Helm release. They allow you to perform tasks like database migrations, initialization, cleanup, and validation during installation, upgrade, or deletion.
Hooks are defined as annotations on Kubernetes resources and are managed by Helm during the release lifecycle.
pre-install
post-install
pre-upgrade
post-upgrade
pre-delete
post-delete
test
helm test to validate the installation. These are not run during normal installation/upgrade.pre-rollback
post-rollback
Hooks are defined using the helm.sh/hook annotation on Kubernetes resources.
# Pre-install hook example (database migration)
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "my-app.fullname" . }}-db-migration
annotations:
helm.sh/hook: pre-install
helm.sh/hook-weight: "5"
helm.sh/hook-delete-policy: hook-succeeded
spec:
template:
spec:
containers:
- name: migration
image: myapp-migration:latest
env:
- name: DB_URL
value: {{ .Values.database.url }}
command: ["/bin/sh", "-c", "python migrate.py"]
restartPolicy: Never
# Post-install hook example (seeding data)
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "my-app.fullname" . }}-seed-data
annotations:
helm.sh/hook: post-install
helm.sh/hook-weight: "10"
helm.sh/hook-delete-policy: hook-succeeded
spec:
template:
spec:
containers:
- name: seed
image: myapp-seed:latest
env:
- name: DB_URL
value: {{ .Values.database.url }}
command: ["/bin/sh", "-c", "python seed.py"]
restartPolicy: Never
# Pre-upgrade hook (backup before upgrade)
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "my-app.fullname" . }}-backup
annotations:
helm.sh/hook: pre-upgrade
helm.sh/hook-weight: "1"
helm.sh/hook-delete-policy: before-hook-creation
spec:
template:
spec:
containers:
- name: backup
image: myapp-backup:latest
env:
- name: DB_URL
value: {{ .Values.database.url }}
command: ["/bin/sh", "-c", "pg_dump > /backups/pre-upgrade.sql"]
restartPolicy: Never
# Post-upgrade hook (validate after upgrade)
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "my-app.fullname" . }}-validate
annotations:
helm.sh/hook: post-upgrade
helm.sh/hook-weight: "20"
helm.sh/hook-delete-policy: hook-succeeded,hook-failed
spec:
template:
spec:
containers:
- name: validate
image: myapp-validator:latest
command: ["/bin/sh", "-c", "python validate.py"]
restartPolicy: Never
- Use meaningful hook names
- Set appropriate hook weights to control execution order
- Use
hook-delete-policyto manage hook cleanup - Make hooks idempotent (can be run multiple times safely)
- Test hooks thoroughly in different scenarios
helm.sh/hook
helm.sh/hook-weight
helm.sh/hook-delete-policy
helm.sh/hook-skip-install
# Hook with multiple annotations
apiVersion: batch/v1
kind: Job
metadata:
name: migration-job
annotations:
# Hook type (multiple allowed)
helm.sh/hook: pre-install,pre-upgrade
# Weight for ordering (lower = earlier)
helm.sh/hook-weight: "5"
# Delete policy
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
# Skip during install (only run on upgrade)
helm.sh/hook-skip-install: "true"
spec:
template:
spec:
containers:
- name: migration
image: myapp-migration:latest
command: ["python", "migrate.py"]
restartPolicy: Never
hook-succeeded
hook-failed
before-hook-creation
hook-succeeded,hook-failed
# Examples of delete policies
# Delete on success only
metadata:
annotations:
helm.sh/hook-delete-policy: hook-succeeded
# Delete on failure only (for debugging)
metadata:
annotations:
helm.sh/hook-delete-policy: hook-failed
# Delete before each run (clean state)
metadata:
annotations:
helm.sh/hook-delete-policy: before-hook-creation
# Delete regardless of outcome
metadata:
annotations:
helm.sh/hook-delete-policy: hook-succeeded,hook-failed
# Multiple policies
metadata:
annotations:
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
- Use
before-hook-creationto ensure clean state - Use
hook-succeededto clean up successful hooks - Consider
hook-failedfor debugging failed hooks - Multiple policies can be combined with commas
- Test delete policies to avoid orphaned resources
Database Migration
Data Seeding
Backup Before Upgrade
Validation After Upgrade
Cleanup
Health Check
helm test.# Database Migration Hook
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "my-app.fullname" . }}-migration
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-weight: "1"
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
spec:
template:
spec:
containers:
- name: migration
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
command:
- /bin/sh
- -c
- |
python manage.py migrate
echo "Migration completed successfully"
env:
- name: DATABASE_URL
value: {{ .Values.database.url }}
restartPolicy: Never
# Health Check Hook
apiVersion: v1
kind: Pod
metadata:
name: {{ include "my-app.fullname" . }}-health-check
annotations:
helm.sh/hook: test
helm.sh/hook-delete-policy: hook-succeeded
spec:
containers:
- name: health-check
image: curlimages/curl:latest
command:
- /bin/sh
- -c
- |
curl -f http://{{ include "my-app.fullname" . }}:{{ .Values.service.port }}/health
echo "Health check passed"
restartPolicy: Never
- Make hooks idempotent (safe to run multiple times)
- Use appropriate weights for ordering
- Test hooks in isolation
- Handle failures gracefully
- Use appropriate delete policies to avoid resource accumulation
# Dry-run to see hooks
helm install my-release ./my-chart --dry-run --debug
# See hook execution order
helm install my-release ./my-chart --dry-run --debug | grep -A 10 hooks
# Check hook status
kubectl get jobs --all-namespaces | grep -E "pre|post|hook"
# View hook logs
kubectl logs <hook-job-pod>
# Test hooks in isolation
# Use --set to enable/disable hooks
# Force hook execution
helm install my-release ./my-chart --set hooks.enabled=true
# Skip hooks
helm install my-release ./my-chart --set hooks.enabled=false
# Debug hook failures
kubectl describe job <hook-job>
kubectl logs <hook-pod>
# Check hook annotations
kubectl get job <hook-job> -o yaml | grep -A 5 annotations
- Hooks not executing: Check annotations and hook type
- Hook failures: Check logs and resources
- Orphaned hooks: Check delete policies
- Order issues: Check hook weights
- Resource conflicts: Check for name collisions
helm.sh/hook-weight annotation. Hooks with lower weights execute first. If weights are equal, the order is not guaranteed.helm.sh/hook-delete-policy annotation. Options include hook-succeeded, hook-failed, and before-hook-creation.helm test. It validates the installation and can be used for health checks and verification.Helm hooks enable powerful lifecycle management in your charts. Use them to automate tasks like database migrations, backups, and validation, making your deployments more robust and reliable.