Zero‑Downtime Rolling Updates for Nomad Jobs: A Step‑by‑Step Guide
A concise, step‑by‑step guide to performing zero‑downtime rolling updates of a Nomad job, covering prerequisites, job configuration, deployment commands, validation checks, and rollback options.
20 Apr 2026, 23:59 UTC

Desired Outcome
Deploy a new version of a service without any downtime by using Nomad’s built‑in rolling update mechanism. Healthy allocations stay running while new ones are started, and old allocations are only drained after the replacements pass their health checks.
Prerequisites
- A Nomad cluster running v1.0 or later (earlier versions lack canary and advanced update stanzas).
- Nomad CLI installed and authenticated (ACL token with
job:writeandnode:readpermissions). - A job specification that includes an
updatestanza definingmax_parallel,health_check, andmin_healthy_time. - Enough free resources on the cluster to run both the old and new allocations simultaneously (at least
max_parallelextra task slots). - Optional: Consul integration for service‑discovery health checks.
Job Configuration Example
The following snippet shows a minimal Docker job with a rolling‑update stanza. Adjust the image tag, resource limits, and health‑check endpoint to match your service.
job "api" {
datacenters = ["dc1"]
type = "service"
update {
max_parallel = 2 # number of new allocations started at once
health_check = "checks" # wait for Consul/Nomad checks to pass
min_healthy_time = "30s" # allocation must stay healthy this long
healthy_deadline = "5m" # give up after this if health never passes
progress_deadline = "10m" # overall rollout timeout
canary = 1 # start a single canary before full rollout
}
group "api" {
count = 6
task "api" {
driver = "docker"
config {
image = "myorg/api:v2.3.1" # <-- change this tag for a new release
port_map {
http = 8080
}
}
resources {
cpu = 500
memory = 256
}
service {
name = "api"
port = "http"
check {
type = "http"
path = "/health"
interval = "10s"
timeout = "2s"
}
}
}
}
}
Procedure
- Edit the job file – change the Docker image tag (or binary version) to the new release.
- Preview the changes – run the plan command from a workstation that has access to the Nomad API:
Verify that the plan shows the expected number of allocations to be created and destroyed, and thatnomad job plan api.nomad.hclmax_paralleldoes not exceed available capacity. - Apply the update – use the
-check-indexflag to avoid race conditions if the job was modified concurrently:
Required permission:nomad job run -check-index $(nomad job inspect -json api | jq -r '.JobModifyIndex') api.nomad.hcljob:writeon the target namespace. - Monitor the rollout – watch the deployment status:
For a specific allocation, use:nomad job status api
The UI (typicallynomad alloc status -short <alloc-id>http://:4646) also shows a live deployment graph. - Adjust canary if needed – if the canary allocation fails health checks, Nomad pauses the deployment. Inspect logs with
nomad alloc logs -stderr <alloc-id>, fix the issue, then resume:nomad job resume api
Validation Checks
- All new allocations running and healthy –
nomad job status apishould listDesired Status = runand theDeployedversion matching the new image tag. - Old allocations drained only after new ones are healthy – verify that the allocation count never drops below the
min_healthy_timethreshold. - Service discovery reflects the new version – if using Consul:
The output should show only instances registered with the new image tag (or the updatedconsul catalog service -service=apimeta.versionif you set it). - Application endpoints respond correctly – send a request to the service endpoint (e.g.,
curl -s http://api.service.consul/health) and confirm the expected JSON payload or HTTP 200. - No failed allocations in UI/logs – the Nomad UI deployment page should show a green “Successful” status; allocation logs should contain no error traces.
Rollback & Recovery
If the new version fails health checks, Nomad automatically pauses the deployment. You have two practical recovery paths:
- Fix and resume – after correcting the image, configuration, or health‑check definition, run
nomad job resume apito continue the rollout. - Revert to the previous version – Nomad keeps a history of job versions. Revert with:
This command restores the last successfully deployed version and starts a new rolling update back to the known‑good state. You can also specify a specific version index:nomad job revert apinomad job revert -job-version=3 api.
Risk note: Reverting also follows the update stanza constraints, so capacity must still allow the old allocations to be placed.
Limitations & Practical Tips
max_parallelmust be ≤ the number of nodes with spare capacity; otherwise the deployment stalls with “failed to place allocation” errors.- Overly aggressive health checks (short intervals, low timeouts) can mark healthy tasks as unhealthy, causing unnecessary rollbacks. Tune
intervalandtimeoutto realistic service start‑up times. - Nomad versions before 0.10 lack the
canaryandprogress_deadlinefields; verify cluster version withnomad versionbefore relying on them. - When using Consul, ensure the service registration TTL/health check matches Nomad’s
health_check = "checks"setting; mismatches can cause Nomad to consider an allocation healthy while Consul still marks it critical.
Quick Verification Checklist
| Check | Command | Expected Result |
|---|---|---|
| Job deployment status | nomad job status api | Desired Status = run, Deployed version = new tag |
| Allocation health | nomad alloc status -short <alloc-id> | State = running, Checks = healthy |
| Consul service catalog | consul catalog service -service=api | Only new version entries present |
| Endpoint response | curl -s http://api.service.consul/health | HTTP 200 with expected payload |
Follow this guide each time you ship a new container image or binary. The rolling‑update stanza gives you deterministic, zero‑downtime deployments as long as capacity and health‑check settings are sized for your workload.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.