Lesson 7 · This repo's library-chart architecture
Hooks & lifecycle
Running work at the right moment of a release — the DB-migration hook, ordered before everything else.
Your win: explain what a Helm hook is, the install/upgrade lifecycle
points, how hook-weight and hook-delete-policy work, and read this
repo's migration hook — including its surprising "local only" gate.
Hooks — intervene in the release lifecycle
Sometimes you must do something at a specific point of a release: run a DB migration before the new code starts, provision a topic, seed data. A hook is just a normal Kubernetes resource with a special annotation that tells Helm when to apply it.1
| Hook | Fires |
|---|---|
pre-install / pre-upgrade | after templates render, before resources are applied |
post-install / post-upgrade | after all resources are applied & ready |
pre-delete / post-delete | around release uninstall |
hook-weight order
(negative first) — so a lower weight runs earlier.1
hook-delete-policy controls cleanup: before-hook-creation (delete
the previous run before re-creating), hook-succeeded, or
hook-failed. Caveat: resources created by a hook are not tracked by the
release, so helm uninstall won't remove them unless a delete-policy says so.
This repo's migration hook
<svc>-migrate Job
libs/util/templates/_hook_migration.tpl:5-127 defines a
batch/v1 Job, util.hook.migrate, annotated
(:12-14):
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "-47"
"helm.sh/hook-delete-policy": before-hook-creation
Its initContainer
migrate-sql runs gjob sql_migrate — the
forward-only migrations from the Postgres course — before the new server pods start.
So a deploy that ships a schema change migrates first, then rolls out the code.
pre-install/pre-upgrade hooks so
they exist before the migrate Job, ordered by weight (lowest first):
- ServiceAccount
-50(_serviceaccount.tpl:58) - Secret
-49(_secret.tpl:14) - ConfigMap
-48(_configmap.tpl:14) - migrate Job
-47
preHookUpsertStream/preHookUpsertKafkaTopic
(for Kafka/NATS provisioning) or migration being enabled.
migrationEnabled AND vendor ≠ synersia AND
regexMatch "^local$" on the environment. So this Helm hook runs migrations
only in local. In staging/prod, migrations go through a different path
(deployments/job.bash), not this hook — a deliberate separation
so production schema changes aren't coupled to every chart upgrade. Don't claim "Helm migrates
prod here" — it doesn't.
Helm docs — Chart Hooks
The hook annotations, the full lifecycle-point list, weights, and delete policies (and the "hooks aren't tracked by the release" caveat).
Check yourself (from memory)
Q1. A Helm hook is fundamentally…
helm.sh/hook — Helm
applies it at that lifecycle point instead of with the main release.
Q2. Among hooks in the same phase, order is set by…
Q3. In this repo, the migration hook runs…
regexMatch "^local$"; prod migrations
go through job.bash, not this hook.
helm.sh/hook so
Helm applies it at a lifecycle point: pre/post-install,
pre/post-upgrade, pre/post-delete. pre-install/upgrade
fires AFTER render, BEFORE resources apply. Order within a phase = hook-weight
ASCENDING (negatives first); hook-delete-policy = cleanup
(before-hook-creation/hook-succeeded/hook-failed).
Caveat: hook-created resources aren't release-tracked, so uninstall may not remove them.
REPO: <svc>-migrate Job (_hook_migration.tpl) is
pre-install,pre-upgrade, weight -47, runs gjob sql_migrate before
pods; ordered after SA(-50)/Secret(-49)/ConfigMap(-48). GATE: runs LOCAL-ONLY (regexMatch
^local$); prod migrations use job.bash.job.bash), or why hooks aren't tracked by
the release? Ask me.
1. Helm — Chart Hooks (annotations, weights, delete policies).