Job manifest
Minimal example
Section titled “Minimal example”apiVersion: odysseus/v1kind: Jobmetadata: name: api-migratespec: image: registry.delta-telematics.ca/acme/api:1.4.2 command: ["/app/migrate", "up"] networks: [acme-network] restartPolicy: "no" # quoted — bare no is YAML false backoffLimit: 2 activeDeadlineSeconds: 600 ttlAfterFinished: 1h secrets: - name: DB vaultPath: deployments/api/dbJobManifest · testdata/docs-examples/migration-job.yamlJob spec
Section titled “Job spec”Generated from JobSpec. Hand edits to this table are overwritten on the next build — change the Go doc comment, or the generator.
| Field | Type | Required | Default | Mutability | Since |
|---|---|---|---|---|---|
activeDeadlineSeconds |
integer | no | — | in-place | 0.7.6 |
backoffLimit |
integer | no | — | in-place | 0.7.6 |
command |
string[] | no | — | recreate | 0.7.6 |
entrypoint |
string[] | no | — | recreate | 0.7.6 |
environment |
object | no | — | recreate | 0.7.6 |
healthCheck |
HealthCheckSpec | no | — | recreate | 0.7.6 |
image |
string | no | — | recreate | 0.7.6 |
init |
boolean | no | — | recreate | 0.21.1 |
networks |
string[] | no | — | recreate | 0.7.6 |
placement |
PlacementSpec | no | — | recreate | 0.7.6 |
resources |
ResourceSpec | no | — | recreate | 0.7.6 |
restartPolicy |
string | no | — | recreate | 0.7.6 |
secrets |
SecretSpec[] | no | — | recreate | 0.7.6 |
ttlAfterFinished |
string | no | — | in-place | 0.7.6 |
ulimits |
Ulimit[] | no | — | recreate | 0.21.1 |
volumes |
VolumeSpec[] | no | — | recreate | 0.7.6 |
workingDir |
string | no | — | recreate | 0.7.6 |
activeDeadlineSeconds: 0 = no deadline
backoffLimit: nil → 3 (JD6)
command: Command overrides the image’s CMD, as argv. Empty leaves the image default.
entrypoint: Entrypoint overrides the image’s ENTRYPOINT, as argv.
environment: Environment are plain environment variables set on every container. Never
put a credential here — use secrets:, which resolves from Vault at
dispatch and never stores the value.
healthCheck: HealthCheck is the container probe. Only type: exec produces a real
healthcheck; an http or tcp declaration is refused rather than left inert.
image: Image is the fully-qualified container image reference, including an
explicit tag. Never “:latest” in production: an unpinned tag makes a
rollback impossible to describe.
init: Init runs Docker’s tiny init as PID 1 so orphaned processes are reaped.
Omit it to take the platform default, which is on; set false only for an
image that already runs its own init.
networks: Networks are the Docker networks the container joins. Names are
tenant-prefixed for you; a backend should stay off traefik-public.
placement: SP-4; shared: Jobs place too
resources: Resources are the CPU and memory limits and requests, written as
limits/requests rather than as four flat keys.
restartPolicy: RestartPolicy is what Docker does when the container exits. The accepted
values differ by kind and are enforced by each kind’s own validator.
secrets: Secrets are references to material in Vault, injected as environment
variables at dispatch. The value never appears in this document.
ttlAfterFinished: duration; “” = keep
ulimits: Ulimits are the container’s POSIX resource limits. A per-container ulimit
overrides the daemon’s defaults, which is the supported way to raise a
file-descriptor ceiling — never a hand-edited daemon.json.
volumes: Volumes are the named volumes and bind mounts attached to each container.
workingDir: WorkingDir is the directory the process starts in, overriding the image’s
WORKDIR.
resources
Section titled “resources”Generated from ResourceSpec. Hand edits to this table are overwritten on the next build — change the Go doc comment, or the generator.
| Field | Type | Required | Default | Mutability | Since |
|---|---|---|---|---|---|
limits |
ResourceValues | no | — | recreate | 0.1.0 |
requests |
ResourceValues | no | — | recreate | 0.1.0 |
ulimits
Section titled “ulimits”Generated from Ulimit. Hand edits to this table are overwritten on the next build — change the Go doc comment, or the generator.
| Field | Type | Required | Default | Mutability | Since |
|---|---|---|---|---|---|
hard |
integer | no | — | recreate | 0.21.1 |
name |
string | no | — | recreate | 0.21.1 |
soft |
integer | no | — | recreate | 0.21.1 |
healthCheck
Section titled “healthCheck”Generated from HealthCheckSpec. Hand edits to this table are overwritten on the next build — change the Go doc comment, or the generator.
| Field | Type | Required | Default | Mutability | Since |
|---|---|---|---|---|---|
command |
any | no | — | recreate | 0.1.0 |
interval |
string | no | — | recreate | 0.1.0 |
path |
string | no | — | recreate | 0.1.0 |
port |
integer | no | — | recreate | 0.1.0 |
retries |
integer | no | — | recreate | 0.1.0 |
startPeriod |
string | no | — | recreate | 0.1.0 |
timeout |
string | no | — | recreate | 0.1.0 |
type |
string | no | — | recreate | 0.1.0 |
command: Command is the probe command, in either the shell-string or the argv-list
form (see ShellOrArgv). Both land on the same stored []string.
interval — There is no floor. Clamping an interval upward would delay failure detection, so
unlike the timeout it is not safety-monotonic — a longer timeout can only reduce
spurious kills, a longer interval can only slow detection. odysseus spec-audit
reports the value; nothing rejects or changes it.
timeout — There is a 10s floor for exec probes: a timed-out exec is SIGKILLed and reparented to a
PID 1 that never reaps it, so a shorter value is refused outright on create (code
healthcheck_timeout_below_floor). On a DEPLOYMENT update that omits healthCheck
entirely, the stored value is restored first and THEN clamped up to the floor if it
predates this rule — silently, unless you are reading the response, where it is
disclosed as healthcheck_timeout_clamped. Omit timeout to take Docker’s 30s default,
which already clears the floor; state it explicitly only to set a tighter bound than
the default.
type: http, tcp, exec
volumes
Section titled “volumes”Generated from VolumeSpec. Hand edits to this table are overwritten on the next build — change the Go doc comment, or the generator.
| Field | Type | Required | Default | Mutability | Since |
|---|---|---|---|---|---|
distributedVolumeId |
string | no | — | recreate | 0.63.0 |
readOnly |
boolean | no | — | recreate | 0.1.0 |
source |
string | no | — | recreate | 0.1.0 |
target |
string | no | — | recreate | 0.1.0 |
distributedVolumeId: DistributedVolumeID mounts a DVM volume by its typed ID (#414). Its
PRESENCE is the discriminator — the manifest surface deliberately has
no type key (every plain manifest volume is a bind mount, see
convertVolumeSpecs), so exactly one of source/distributedVolumeId is
set, and the shape validator downstream rejects both-or-neither.
secrets
Section titled “secrets”Generated from SecretSpec. Hand edits to this table are overwritten on the next build — change the Go doc comment, or the generator.
| Field | Type | Required | Default | Mutability | Since |
|---|---|---|---|---|---|
anchor |
string | no | — | recreate | 0.37.0 |
mountPath |
string | no | — | recreate | 0.1.0 |
name |
string | no | — | recreate | 0.1.0 |
rotation |
string | no | — | recreate | 0.1.0 |
vaultPath |
string | no | — | recreate | 0.1.0 |
anchor: Anchor: volume(<id>) | process | external — WP18 S10.
placement
Section titled “placement”Generated from PlacementSpec. Hand edits to this table are overwritten on the next build — change the Go doc comment, or the generator.
| Field | Type | Required | Default | Mutability | Since |
|---|---|---|---|---|---|
affinity |
PlacementSelector | no | — | recreate | 0.7.6 |
antiAffinity |
PlacementSelector | no | — | recreate | 0.7.6 |
node |
string | no | — | recreate | 0.7.6 |
preferredZone |
string | no | — | recreate | 0.7.6 |
residency |
ResidencySpec | no | — | recreate | 0.74.0 |
affinity: Affinity steers placement TOWARD nodes carrying a label. It is a
preference the scorer weighs, not a filter that refuses — a workload with
an unsatisfiable affinity is still placed, just not where it asked.
antiAffinity: AntiAffinity steers placement AWAY from nodes carrying a label, with the
same weigh-do-not-refuse semantics as Affinity.
node: Node pins the workload to one node by name, landing on Deployment.NodeID.
Leave it unset to let the scheduler choose; an empty value never clears an
assignment the scheduler already made.
preferredZone: PreferredZone names an edge zone the scorer prefers.
NOTE, so nobody debugs this twice: no zone is declared in any shipped control-plane config today, so this currently scores against nothing. That is a real finding with its own issue, not a defect in this block.
residency: Residency is where the workload is legally allowed to run (S19, #557).