Balancing Nomad Workloads with Placement Constraints
Nomad’s default bin‑packing often overloads a few nodes. Using placement constraints such as spread and distinct lets you declaratively distribute tasks across zones or racks, improving fairness and fault tolerance.
07 Dec 2025, 02:37 UTC

The Packing Problem
When you submit a batch of services to a Nomad cluster, the scheduler often packs them onto the first few nodes that have free capacity. The result is a lopsided cluster: some hosts run hot while others sit idle, and a single node failure can take down a disproportionate share of your workload.
Why Constraints Help
Nomad’s placement constraints—affinity, anti‑affinity, and spread—let you describe *where* tasks should run instead of leaving the decision entirely to the bin‑packing algorithm. By expressing intent declaratively, you get a more even distribution, better fault isolation, and higher overall utilization without writing custom schedulers.
Worked Example: Spreading Across Availability Zones
Assume a three‑zone cluster (us‑east‑1a, us‑east‑1b, us‑east‑1c). The following job stanza asks Nomad to spread the three task groups evenly across those zones.
job "web‑api" {
datacenters = ["dc1"]
type = "service"
group "api" {
count = 3
constraint {
attribute = "${node.zone}"
operator = "distinct"
value = ""
}
task "server" {
driver = "docker"
config {
image = "myorg/api:v1.2"
ports = ["http"]
}
resources {
cpu = 500
memory = 256
}
}
}
}
The constraint block uses the distinct operator on the node attribute ${node.zone}. Nomad will place each of the three allocations in a different zone, assuming each zone has at least one eligible node.
Trade‑offs and Limits
- Acceptance rate: Overly strict constraints (e.g., requiring a unique zone for ten tasks when only three zones exist) cause the scheduler to reject the job or leave allocations pending.
- Submission‑time evaluation: Constraints are checked when the job is submitted. Changing a constraint later does not move existing allocations; you must stop and reschedule the job to rebalance.
- Version support: The
spreadstanza anddistinctoperator were added in Nomad 1.2. Clusters running older releases will reject the syntax. - Typo sensitivity: A misspelled attribute name or operator results in a validation error at plan time, not a silent misplacement.
Actionable Next Steps
- Audit current jobs: Run
nomad job inspect <job-id>and look for missingconstraintblocks. - Add a spread constraint: Start with a single
distincton a high‑cardinality attribute such as${node.zone}or${node.rack}. - Validate with a test deployment: Submit the job in a staging namespace, then run
nomad status <job-id>and examine theAllocationstable to confirm tasks landed in separate zones. - Monitor continuously: Enable the
nomad alloc statusoutput in your observability pipeline so you can alert when a zone becomes over‑represented.
By turning placement intent into explicit constraints, you give Nomad the information it needs to keep the cluster balanced and resilient—without sacrificing the simplicity that makes Nomad attractive in the first place.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.