Skip to content

How to Configure Kubernetes Topology Spread Constraints

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about How to Configure Kubernetes Topology Spread Constraints. We cover key concepts, practical examples, and best practices.

The Problem

Your pods are concentrated in one availability zone despite using topology spread constraints. When that zone fails, the entire application goes down. The spread constraints either do not distribute pods or prevent scheduling entirely.

Quick Fix

Fix 1: Basic Topology Spread Constraint

WRONG — no spread constraints:

spec:
  replicas: 6
  template:
    spec:
      # no topologySpreadConstraints — pods may all go to one zone

RIGHT — spread across zones:

spec:
  replicas: 6
  template:
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: my-app

This ensures no more than 1 pod difference between zones. With 6 replicas and 3 zones: 2 per zone.

Fix 2: maxSkew Misconfiguration

WRONG — maxSkew too restrictive:

maxSkew: 1
whenUnsatisfiable: DoNotSchedule
# With 3 zones and 4 replicas: can schedule 2+1+1 (max difference is 1, OK)
# With 3 zones and 1 replica: 1+0+0 (max difference is 1, OK)

RIGHT — choose maxSkew based on your tolerance:

# maxSkew: 1 — strictest, allows at most 1 pod difference
# maxSkew: 2 — allows up to 2 pod difference (more flexible)

Fix 3: whenUnsatisfiable Behavior

WRONG — using DoNotSchedule for bursting scenarios:

whenUnsatisfiable: DoNotSchedule
# (during scale-up, pods stay Pending if no zone meets the skew requirement)

RIGHT — use ScheduleAnyway for flexible spreading:

topologySpreadConstraints:
- maxSkew: 2
  topologyKey: topology.kubernetes.io/zone
  whenUnsatisfiable: ScheduleAnyway
  labelSelector:
    matchLabels:
      app: my-app

With ScheduleAnyway, the scheduler does its best but does not block scheduling if constraints cannot be met.

Fix 4: Multiple Topology Keys

Spread across zones first, then hosts:

topologySpreadConstraints:
- maxSkew: 1
  topologyKey: topology.kubernetes.io/zone
  whenUnsatisfiable: DoNotSchedule
  labelSelector:
    matchLabels:
      app: my-app
- maxSkew: 1
  topologyKey: kubernetes.io/hostname
  whenUnsatisfiable: ScheduleAnyway
  labelSelector:
    matchLabels:
      app: my-app

Fix 5: Node Label Selector

WRONG — applying constraints to nodes that do not have the topology label:

kubectl get nodes --show-labels | grep topology.kubernetes.io/zone
# (if no zones are labeled, the constraint has no effect)

RIGHT — label nodes with zones:

kubectl label node worker-1 topology.kubernetes.io/zone=us-east-1a
kubectl label node worker-2 topology.kubernetes.io/zone=us-east-1b
kubectl label node worker-3 topology.kubernetes.io/zone=us-east-1c

Fix 6: Check Skew Violations

kubectl describe pod my-app-xyz
# Events:
#   Type     Reason            Age   From               Message
#   Warning  TopologySpread    10s   default-scheduler  Found 3 matching pods, max skew is 2
kubectl get pods -o wide --selector=app=my-app
# NAME          READY   NODE
# my-app-1      Running  worker-1 (us-east-1a)
# my-app-2      Running  worker-1 (us-east-1a)  ← skew violation
# my-app-3      Running  worker-2 (us-east-1b)

Use DodaTech's Topology Visualizer to see pod distribution across zones and nodes, and simulate constraint changes before applying them.

Prevention

  • Label nodes with zone/region topology keys.
  • Use DoNotSchedule for production-critical spreading.
  • Use ScheduleAnyway for development or burstable workloads.
  • Set nodeAffinity to restrict constraint evaluation to specific nodes.
  • Monitor kube-scheduler metrics for constraint violations.

Common Mistakes with topology spread

  1. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  2. Using return to exit a function early instead of wrapping a pure value in the monad
  3. Mixing let bindings with <- bindings in do notation, producing type errors

These mistakes appear frequently in real-world K8S code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### What is the difference between topology spread constraints and pod anti-affinity?

Topology spread constraints distribute pods evenly across topology domains (zones, hosts). Pod anti-affinity prevents co-location of pods with specific labels. Topology spread is more flexible and handles multiple domains simultaneously.

How does maxSkew=1 work with an odd number of replicas?

With 3 zones and 5 replicas, the scheduler distributes as 2+2+1 (max difference is 1, so the difference between any two zones is at most 1). With 3 zones and 4 replicas: 2+1+1.

Can I use topology spread constraints with DaemonSets?

Yes, DaemonSets support topology spread constraints in Kubernetes 1.24+. This spreads DaemonSet pods across zones even though each node gets only one pod. Use topologyKey: topology.kubernetes.io/zone to schedule at least one pod per zone.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro