
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Clusters that ignore physical topology are fragile, regardless of how many replicas you run. Topology Spread Constraints in Kubernetes solve this by instructing the scheduler to distribute pods evenly across defined failure domains like zones, nodes, or racks. Without these constraints, a single zone outage can silently wipe out your entire service even with ten replicas configured. This guide provides the exact configuration patterns and mathematical logic needed to guarantee true high availability in production environments.
What Are Topology Spread Constraints in Kubernetes and Why Do They Matter?
The default Kubernetes scheduler optimizes for resource packing and immediate schedulability, not necessarily for fault isolation. Left unconstrained, the scheduler might place all replicas of a critical microservice on nodes within the same availability zone simply because those nodes had available CPU at scheduling time. When that zone experiences an outage — a common occurrence in cloud regions from AWS us-east-1 to GCP asia-south1 — every replica fails simultaneously. Properly configuring blue-green and canary deploys on Kubernetes helps with safe rollouts, but only topology awareness prevents correlated infrastructure failures from causing total service loss.
Topology spread constraints operate at the scheduler level, evaluating candidate nodes against a mathematical skew formula before binding a pod. Unlike pod anti-affinity rules which are binary (either satisfy or fail), spread constraints allow controlled imbalance through the maxSkew parameter. This flexibility means your deployment can still proceed during partial capacity issues rather than stalling entirely. For teams managing stateful workloads or databases, understanding this distinction is critical before attempting PostgreSQL replication and high availability setups where uneven distribution causes replication lag or split-brain scenarios.
How Do You Configure maxSkew and whenUnsatisfiable Correctly?
The two most misunderstood fields in topology spread constraints are maxSkew and whenUnsatisfiable. Getting these wrong either creates false security or causes unnecessary scheduling failures. The maxSkew value defines the maximum permitted difference in pod count between any two topology domains. If you set maxSkew: 1 across three zones, the scheduler ensures no zone has more than one pod difference from any other zone. With six replicas, valid distributions include 2-2-2 or 2-3-1, but never 4-1-1.
Choosing Between DoNotSchedule and ScheduleAnyway
The whenUnsatisfiable field determines scheduler behavior when no placement satisfies the maxSkew constraint. In production systems requiring strict compliance or genuine HA, always use DoNotSchedule. This leaves pods in Pending state rather than violating your topology guarantees. Use ScheduleAnyway only for batch jobs or non-critical workloads where some distribution is better than none. A common mistake in Nepal-based deployments targeting Singapore or Mumbai regions is setting ScheduleAnyway during testing and forgetting to change it before production promotion, leaving services vulnerable during regional incidents.
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
spec:
replicas: 6
selector:
matchLabels:
app: payment-service
template:
metadata:
labels:
app: payment-service
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: payment-service
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: payment-service
containers:
- name: payment-api
image: payments:v2.4.1
resources:
requests:
cpu: 500m
memory: 512Mi This configuration applies two constraints simultaneously: first spreading across zones, then across individual nodes within each zone. The order matters — the scheduler evaluates constraints sequentially, and earlier constraints take precedence when conflicts arise. Always pair spread constraints with explicit resource requests; without them, the scheduler cannot accurately predict whether a node can accommodate additional pods, leading to suboptimal spreading or cascading pending states.
How Does Topology Spread Compare to Pod Anti-Affinity?
Many engineers default to pod anti-affinity rules because they existed before topology spread constraints reached GA status. While both mechanisms influence pod placement, their operational characteristics differ significantly. Understanding when to use each prevents over-constraining your cluster or creating unschedulable deployments during scaling events. Refer to Kubernetes resource limits and requests guidance to ensure your spreading strategy aligns with actual capacity planning rather than theoretical distribution.
| Criteria | Topology Spread Constraints | Pod Anti-Affinity |
|---|---|---|
| Distribution Model | Soft balancing with configurable skew tolerance | Hard exclusion or soft preference (binary) |
| Scaling Behavior | Graceful degradation when domains exhaust | Pods pend immediately if no valid domain exists |
| Multi-Domain Support | Native support for zone + node + custom keys | Requires separate rule per topology key |
| Operational Complexity | Single declarative block covers most HA needs | Multiple rules needed for equivalent coverage |
| Best For | Stateless services, web frontends, API layers | Strict singleton enforcement, leader election |
In practice, I recommend topology spread constraints as the default for 90% of workloads. Reserve pod anti-affinity for cases where you absolutely cannot tolerate co-location, such as etcd members or database primaries. Combining both is valid but increases scheduling latency and debugging complexity. If your team struggles with frequent Pending pods after adopting spread constraints, the issue usually stems from insufficient node capacity in specific domains rather than misconfiguration — check your Cluster Autoscaler settings and ensure it can provision nodes in all targeted zones.
What Happens When Capacity Is Uneven Across Zones?
Real-world clusters rarely have perfectly symmetric capacity. One zone might have older instance types, reserved capacity limitations, or spot interruptions. When a zone cannot accept additional pods while satisfying maxSkew, the scheduler's behavior depends entirely on your whenUnsatisfiable setting. With DoNotSchedule, new pods remain Pending until capacity rebalances or you manually intervene. This is correct behavior for HA-critical services but requires proactive monitoring.
Set up alerts on kube_pod_status_unschedulable metrics filtered by your spread-constrained deployments. In my experience supporting SOC 2 compliant environments, auditors specifically check whether teams monitor for topology violations and have documented remediation procedures. Consider implementing a secondary fallback constraint with ScheduleAnyway and higher maxSkew for graceful degradation during extended capacity issues. This pattern maintains partial topology awareness while preventing complete deployment stalls.
- Audit node labels quarterly to ensure
topology.kubernetes.io/zonevalues match actual cloud provider zones - Test zone failure scenarios in staging using chaos engineering tools before relying on spread constraints in production
- Combine spread constraints with Pod Disruption Budgets to maintain minimum availability during voluntary disruptions
- Document your maxSkew rationale in deployment manifests — future engineers need context for why 1 was chosen over 2
- Review pending pod events weekly to identify chronic capacity imbalances before they cause incidents
How Do You Validate and Debug Topology Distribution in Production?
Configuration alone doesn't guarantee correct behavior. You must validate that pods actually distribute as intended after deployment. The most direct method uses kubectl with custom columns to visualize distribution:
kubectl get pods -l app=payment-service \
-o custom-columns='NAME:.metadata.name,ZONE:.metadata.labels.topology\.kubernetes\.io/zone,NODE:.spec.nodeName' \
--sort-by='.metadata.labels.topology\.kubernetes\.io/zone' For continuous validation, implement admission controllers or OPA policies that reject deployments missing required spread constraints for critical labels. This shifts compliance left and prevents drift. When debugging unexpected distribution, check three things first: verify label selectors match exactly (typos here silently disable constraints), confirm nodes have correct topology labels, and ensure replica count exceeds the number of topology domains (you cannot achieve maxSkew:1 with 2 replicas across 3 zones).
Integrate topology validation into your CI/CD pipeline using tools like kube-score or conftest. These catch misconfigurations before they reach production. For teams operating under ISO 27001 or similar frameworks, maintain evidence of topology validation runs as part of your change management documentation. Auditors appreciate seeing automated proof that HA controls function as designed, not just configuration files claiming they should.
Implementing Resilient Pod Distribution Today
Topology Spread Constraints in Kubernetes transform theoretical high availability into enforced operational reality. Start by adding zone-level spread constraints to your three most critical services this week, using maxSkew: 1 and DoNotSchedule. Validate distribution with the kubectl command provided above, then add Prometheus alerting for unschedulable pods. Once confident, extend to node-level spreading and integrate policy-as-code checks into your deployment pipeline. If your team needs help designing topology-aware architectures that pass compliance audits without sacrificing velocity, reach out to discuss your specific infrastructure challenges.