Repository navigation
Helm Hooks and Lifecycle
Helm hooks are ordinary Kubernetes resources with helm.sh/hook annotations. Timonel does not need
a special hook resource type: attach the annotations to a typed cdk8s-plus construct whenever the
construct supports the Kubernetes resource you need.
Common annotations are:
helm.sh/hook
helm.sh/hook-weight
helm.sh/hook-delete-policy
Common hook events include:
pre-install
post-install
pre-upgrade
post-upgrade
pre-delete
post-delete
test
Consult the Helm documentation for the complete lifecycle semantics supported by your Helm version.
import * as kplus from 'cdk8s-plus-33';
import { Rutter } from 'timonel';
const chart = new Rutter({
meta: { name: 'orders', version: '1.0.0' },
});
new kplus.Job(chart.getChart(), 'DatabaseMigration', {
metadata: {
name: 'orders-migrate',
annotations: {
'helm.sh/hook': 'pre-install,pre-upgrade',
'helm.sh/hook-weight': '-10',
'helm.sh/hook-delete-policy': 'before-hook-creation,hook-succeeded',
},
},
backoffLimit: 2,
containers: [
{
name: 'migration',
image: 'ghcr.io/example/orders-migrate:1.0.0',
},
],
});The hook is still a normal Kubernetes Job in the synthesized chart.
new kplus.Job(chart.getChart(), 'SmokeTest', {
metadata: {
name: 'orders-smoke-test',
annotations: {
'helm.sh/hook': 'post-install,test',
'helm.sh/hook-weight': '10',
'helm.sh/hook-delete-policy': 'hook-succeeded',
},
},
backoffLimit: 1,
containers: [
{
name: 'smoke-test',
image: 'curlimages/curl:8.16.0',
command: ['sh', '-c', 'curl --fail http://orders/health'],
},
],
});Pin image versions in real environments according to your supply-chain policy.
Helm hook weights are strings containing signed integers. Lower weights run first within the same hook lifecycle stage.
Example ordering:
-20 create prerequisites
-10 run schema migration
0 default hook work
10 smoke test
Do not rely on incidental file ordering for lifecycle behavior.
Common values include:
before-hook-creation
hook-succeeded
hook-failed
Choose a policy based on whether you need historical Jobs for debugging. Deleting both successful and failed hooks can make incident analysis harder.
If a hook needs Kubernetes API access, create a dedicated ServiceAccount and only the permissions it needs. Do not automatically reuse a broad application or cluster-admin identity.
Timonel's AWS IRSA helper can be used when a hook also needs AWS permissions:
const serviceAccount = chart.addAWSIRSAServiceAccount({
name: 'migration',
roleArn: 'arn:aws:iam::123456789012:role/orders-migration',
});Attach the ServiceAccount to the workload using the supported cdk8s-plus workload API for the version you have installed.
If a hook field must depend on Helm values, use ValuesRef where the serialized structure supports it. Do not convert the entire Job to raw YAML just to template one field.
For a custom hook resource without a typed construct, object-form addManifest(object, id) remains
the narrow fallback.
First validate syntax and normal rendering:
helm lint ./dist/orders
helm template orders ./dist/ordersThen use an isolated cluster or namespace to validate real hook ordering and failure behavior:
helm upgrade --install orders ./dist/orders --namespace orders --create-namespace
helm test orders --namespace orders
kubectl get jobs -n orders- make hooks idempotent when they may run again after a failed release;
- set bounded retry/backoff behavior;
- use immutable images;
- keep hook permissions narrow;
- avoid embedding credentials in hook commands or values files;
- keep migrations backward compatible with the application rollout when possible;
- test install, upgrade, rollback, and uninstall paths separately.
Timonel documentation · Repository · npm · Issues