Lesson 15 Hooks & Tests
Theme:
Lesson 15 · Slide 1

Hooks & Tests

Orchestrate lifecycle actions and validate releases with Helm hooks and tests.

Lesson 15 · Slide 2

Helm Hook Lifecycle Events

Hooks let you intervene at specific points during a release lifecycle:

HookWhen It Runs
pre-installAfter templates render, before any resources are created
post-installAfter all resources are loaded into Kubernetes
pre-upgradeAfter templates render, before any resources are updated
post-upgradeAfter all resources are updated
pre-deleteBefore any resources are deleted from Kubernetes
post-deleteAfter all resources are deleted
pre-rollbackBefore any resources are rolled back
post-rollbackAfter all resources are rolled back
Notes: Hook resources are not managed as part of the release. They are created, run, and optionally cleaned up separately from the main resource set.
Lesson 15 · Slide 3

Hook Annotations

Three annotations control hook behaviour:

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "mychart.fullname" . }}-db-migrate
  annotations:
    "helm.sh/hook": pre-upgrade
    "helm.sh/hook-weight": "-5"
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: migrate
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          command: ["python", "manage.py", "migrate"]
Lesson 15 · Slide 4

Hook Weights & Delete Policies

Hook Weights

Hooks execute in ascending weight order. Hooks with the same weight run in name order.

# Runs first (weight -10)
annotations:
  "helm.sh/hook": pre-upgrade
  "helm.sh/hook-weight": "-10"

# Runs second (weight 0, default)
annotations:
  "helm.sh/hook": pre-upgrade
  "helm.sh/hook-weight": "0"

# Runs third (weight 5)
annotations:
  "helm.sh/hook": pre-upgrade
  "helm.sh/hook-weight": "5"

Delete Policies

PolicyBehaviour
before-hook-creationDelete previous hook resource before launching new one
hook-succeededDelete after hook succeeds
hook-failedDelete if the hook fails
Notes: before-hook-creation is the most common choice — it prevents "already exists" errors on repeated upgrades.
Lesson 15 · Slide 5

Common Hook Patterns

Backup Before Upgrade

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "mychart.fullname" . }}-backup
  annotations:
    "helm.sh/hook": pre-upgrade
    "helm.sh/hook-weight": "-10"
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: backup
          image: postgres:16
          command:
            - pg_dump
            - -h
            - {{ .Values.db.host }}
            - -U
            - {{ .Values.db.user }}
            - -f
            - /backups/pre-upgrade.sql

Slack Notification After Deploy

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "mychart.fullname" . }}-notify
  annotations:
    "helm.sh/hook": post-upgrade
    "helm.sh/hook-weight": "10"
    "helm.sh/hook-delete-policy": hook-succeeded
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: notify
          image: curlimages/curl:8.5.0
          command:
            - curl
            - -X
            - POST
            - -H
            - "Content-type: application/json"
            - -d
            - '{"text":"Release {{ .Release.Name }} upgraded to {{ .Chart.Version }}"}'
            - {{ .Values.slack.webhookUrl }}
Lesson 15 · Slide 6

Helm Tests — helm test

A test is simply a pod with the helm.sh/hook: test annotation. Helm considers the test passed if the pod exits with code 0.

apiVersion: v1
kind: Pod
metadata:
  name: {{ include "mychart.fullname" . }}-test-connection
  labels:
    {{- include "mychart.labels" . | nindent 4 }}
  annotations:
    "helm.sh/hook": test
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  restartPolicy: Never
  containers:
    - name: curl-test
      image: curlimages/curl:8.5.0
      command:
        - curl
        - --fail
        - --silent
        - --show-error
        - http://{{ include "mychart.fullname" . }}:{{ .Values.service.port }}/healthz
# Run tests against a release
helm test my-release

# Run with increased timeout
helm test my-release --timeout 5m0s

# View test logs on failure
helm test my-release --logs
Lesson 15 · Slide 7

Writing Effective Tests

Connectivity Test

apiVersion: v1
kind: Pod
metadata:
  name: {{ include "mychart.fullname" . }}-test-dns
  annotations:
    "helm.sh/hook": test
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  restartPolicy: Never
  containers:
    - name: dns-check
      image: busybox:1.36
      command:
        - nslookup
        - {{ include "mychart.fullname" . }}

Data Verification Test

apiVersion: v1
kind: Pod
metadata:
  name: {{ include "mychart.fullname" . }}-test-data
  annotations:
    "helm.sh/hook": test
    "helm.sh/hook-weight": "5"
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  restartPolicy: Never
  containers:
    - name: data-check
      image: postgres:16
      env:
        - name: PGPASSWORD
          valueFrom:
            secretKeyRef:
              name: {{ include "mychart.fullname" . }}
              key: postgres-password
      command:
        - psql
        - -h
        - {{ include "mychart.fullname" . }}
        - -U
        - postgres
        - -c
        - "SELECT 1;"
Notes: Use hook-weight on tests to control order: check DNS first (weight 0), then HTTP health (weight 5), then data integrity (weight 10).
Lesson 15 · Slide 8

Summary

Next: Lesson 16 →

1 / ?