Jobs
jobs renders one Job per key, on the same container model as deployments and cron jobs. A job runs once and exits, which makes it the right tool for migrations, seeding, and other one-off tasks. A bare key produces a single container named after the key:
jobs:
migrate: # one container named "migrate", runs onceMost jobs set a command:
jobs:
database-migrations:
command: ["/app/bin", "database-migrate"]For a release named test, that renders Job/test-job-database-migrations. The job- prefix keeps it from colliding with a deployment or cron job that shares the key. See Naming.
Defaults
Each job is generated with safe defaults you can override per job:
| Field | Default | Meaning |
|---|---|---|
restartPolicy | Never | A failed pod is not restarted in place. |
backoffLimit | 0 | A failed job is not retried. |
ttlSecondsAfterFinished | 600 | The finished job is cleaned up after 10 minutes. |
jobs:
import:
backoffLimit: 3 # retry a failed run up to three times
ttlSecondsAfterFinished: 3600 # keep the finished job for an hour
command: ["/app/bin", "import"]Helm hooks
A plain job is part of the release: it runs on every helm install and helm upgrade as an ordinary resource. To run it at a specific point in the release lifecycle instead, set hook. That is how you run migrations before the new pods start:
jobs:
database-migrations:
hook: pre-install,pre-upgrade
command: ["/app/bin", "database-migrate"]hook maps to the helm.sh/hook annotation. Two optional keys tune the rest of the hook behavior:
| Key | Annotation | Default |
|---|---|---|
hook | helm.sh/hook | none (job is a normal release resource) |
hook-weight | helm.sh/hook-weight | 10 |
hook-policy | helm.sh/hook-delete-policy | before-hook-creation |
jobs:
seed:
hook: post-install
hook-weight: "5" # lower weights run first
hook-policy: hook-succeeded # delete the job once it succeeds
command: ["/app/bin", "seed"]The database-migrations job above renders these annotations onto the Job:
metadata:
name: test-job-database-migrations
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "10"
"helm.sh/hook-delete-policy": before-hook-creationThese are default annotations the chart owns and always win, so a hook job cannot have the three keys overwritten by user annotations. See the Helm hooks reference for the full list of hook points and delete policies.
Hooks and config
A job with a hook runs at a point where the release-wide config may not exist yet, so its config follows the hook:
- A
pre-install,pre-upgrade,pre-rollbackorpre-deletejob doesn't read the release-wide config. Helm applies it after the first three phases, and atpre-deleteit is missing when the install failed before applying it. These jobs all read<fullname>-pre-hook-variables(-secrets,-sealed-secrets,-files,-secret-files,-sealed-secret-files), one shared copy of the release-wide config, created one weight below the first of them in each of their phases. - A
post-deletejob reads<fullname>-post-hook-*, the same kind of copy, because the release-wide config is gone by then. Apost-install,post-upgradeorpost-rollbackjob reads the release-wide config directly. - A hook job's own config holds only its own keys and is a hook resource one weight below the job. The job reads it after the shared copy, so its keys win.
- Helm deletes hook config once the phase finishes. If a job fails, its config stays until the next run replaces it.
Helm creates hook resources one at a time, each with its own create and watch, so one shared copy per group keeps the number of hook resources down, however many jobs read it. Helm doesn't wait for a SealedSecret to be unsealed: the controller unseals it within seconds, and a job that starts earlier has its pod retried until the Secret exists.
Chart-created persistence volumes are not available to pre-install, pre-upgrade or pre-rollback jobs. With sealedSecretsScope: strict the chart refuses to render a pre-hook or post-delete job, see Scope.
Containers and pod settings
A job carries the same pod and container fields as a deployment, and pod-level values cascade to its containers. Declare containers explicitly for more than one, or to set container-level fields:
jobs:
migrate:
containers:
migrate:
image: myorg/app:1.4.0
command: ["/app/bin", "migrate"]
configure:
secrets: true # mount the release's Secret into this containerSee Conventions for the bare-key form and cascading. Job pods do not carry the rollout checksum annotations that deployments do, since each run starts a fresh pod anyway.
Disabling a job
Set enabled: false to keep a job in values but skip rendering it:
jobs:
backfill:
enabled: false
command: ["/app/bin", "backfill"]