Run-to-completion work such as migrations, smoke checks, and one-off backfills.
You declare tasks next to components in deployah.yaml. Deployah runs hook
tasks around deploy, and you run any task yourself with deployah run.
Point the task at a component with from so it reuses that image and env.
Set "on": preDeploy so it runs before the app starts on every install and
upgrade. Quote "on" in YAML 1.1 so it is not read as a boolean.
apiVersion: v1-alpha.5
project: shop
components:
api:
image: ghcr.io/acme/shop:1.2.3
env:
DATABASE_URL: ${DATABASE_URL}
tasks:
migrate:
from: api
"on": preDeploy
command: ["migrate", "up"]from copies env, environments, profiles, and resources. It also copies
envFile and configFile paths, but those files are not mounted on the Job
yet (same as components). It does not copy command, args, or service fields
such as port. Profiles apply to the Job: node selector, tolerations, and
security context. Task env overlays the parent map. Runtime secrets for
tasks go in env: (inherited or overlay). ${...} substitution works the
same as elsewhere in the spec.
command is required when the task uses the parent image. If you set image
on the task, command is optional.
tasks:
smoke:
from: api
"on": postDeploy
command: ["curl", "-f", "http://api/health"]on is one value: preDeploy, postDeploy, manual, or schedule. To run the same
command before and after deploy, define two tasks that share from.
after orders tasks inside the same on. The named task must also run in
every environment the dependent runs in. Cross-phase after is an error.
after is not allowed on manual or schedule tasks.
deployah run works for every task, including hooks you want to retry.
It runs only that task, not the tasks in its after list.
deployah run backfill production --yesManual tasks exist only for the CLI. They are not part of the Helm release.
tasks:
backfill:
from: api
"on": manual
command: ["backfill"]Wait is the default. --detach returns after the Job is created. Concurrent
runs are allowed; each run gets a unique Job name.
Set "on": schedule so Deployah creates a Kubernetes CronJob in the release.
deployah deploy applies the CronJob and does not start a Job on that deploy.
Quote "on" in YAML 1.1.
tasks:
cleanup:
from: api
"on": schedule
schedule: "0 3 * * *"
command: ["cleanup"]Fields:
schedule: a 5-field cron expression, a Vixie step such as*/5, a named weekday (sun-sat),?(same as*), or a descriptor (@hourly,@daily,@midnight,@weekly,@monthly,@yearly,@annually,@every 1h). Do not putTZ=orCRON_TZ=in the string; usetimeZone.timeZone: IANA name. Defaults toEtc/UTC. Values other thanEtc/UTCneed Kubernetes 1.27 or later; older API servers drop the field with no error.concurrencyPolicy:Allow,Forbid, orReplace. Defaults toForbid.timeout: how long one run may take. When omitted, the CronJob uses a 1h cluster deadline.deployah rundoes not apply that default; the CLI Job has no cluster deadline unless you settimeout.suspend: whentrue, the CronJob creates no Jobs until you set it back tofalse.
deployah run cleanup dev still creates a one-shot Job. That Job and the
CronJob can overlap. Fanout is an Indexed Job inside the CronJob template.
Forbid with no starting deadline defers the next tick instead of dropping
it: one catch-up run starts when the active run finishes. If a task overruns
its interval, lengthen the interval or split the work.
Setting suspend back to false schedules the missed run at once, not on
the next tick.
@every is a delay from CronJob creation time, so a redeploy shifts the
schedule. Use a cron expression for a fixed wall-clock time.
ttlSecondsAfterFinished deletes finished Jobs before
successfulJobsHistoryLimit can keep them, so kubectl get jobs can be
empty. Leave TTL unset if you want the history limits to apply.
Fanout runs several indexed copies of a task. Use a number as a shortcut
(count, one at a time) or an object. It works on preDeploy, postDeploy,
manual, and schedule.
tasks:
migrate:
from: api
"on": preDeploy
command: ["migrate", "up"]
fanout: 2 # two copies on every deploy
backfill:
from: api
"on": manual
command: ["backfill"]
fanout: 4 # count 4, parallelism 1
# fanout:
# count: 4
# parallelism: 2--count and --parallelism on deployah run override that execution only.
Each copy sees JOB_COMPLETION_INDEX (0, 1, 2, ...). Parallelism is capped at
count and cannot exceed 100000 (the Kubernetes Indexed Job limit).
On a first install, preDeploy runs before Deployments and Services. A
migrate task that talks to Postgres needs that database already reachable
(another release, a managed DB, or a job you ran first). deployah plan
prints this reminder on a fresh install.
deployah logs shop --component=migrate --no-follow
deployah logs shop --component=backfill --no-followThe component label is the task name. Finished Job pods are included, not only running ones.
A Helm rollback does not run tasks. Failed hook Jobs are kept so you can
read logs. Migrations that already ran are not reverted; write a down
migration and deployah run it if you need that.
- Spec reference for every field
- Troubleshooting for a failed hook or a tight timeout