Skip to main content
RunBook Academy

KubernetesXXV · Topology Spread ConstraintsTopology spread

Topology keys — kubernetes.io/hostname, topology.kubernetes.io/zone, and beyond

Advanced⏱ ~16 minkubectlkubeadm

What you'll learn

  • List the standard topology keys and their domains
  • Reason about the cost of each (counting domains)
  • Apply layered topology keys (hostname + zone)
  • Verify the cluster has the right labels

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

The topologyKey field in a topology spread constraint defines the placement domain. The most common keys are kubernetes.io/hostname (per node) and topology.kubernetes.io/zone (per zone). This lesson covers the standard keys, their domains, and how to verify the cluster has the right labels.

The standard keys

Topology keyDomainCost
kubernetes.io/hostnamePer nodeMany domains (one per node)
topology.kubernetes.io/zonePer zoneFew domains (one per zone)
topology.kubernetes.io/regionPer regionFewest domains (one per region)

kubernetes.io/hostname (per node)

topologySpreadConstraints:
- maxSkew: 1
  topologyKey: kubernetes.io/hostname

Each domain is one node. The constraint distributes Pods across nodes; the count is the number of matching Pods per node.

flowchart TB
    A[6 replicas, 6 nodes] --> B["Each node: 1 Pod"]
    B --> C["Skew: 0"]

For a 6-replica Deployment on 6 nodes with maxSkew: 1, each node hosts 1 Pod. With maxSkew: 1 and 3 nodes, distribution [2, 2, 2]; skew 0.

topology.kubernetes.io/zone (per zone)

topologySpreadConstraints:
- maxSkew: 1
  topologyKey: topology.kubernetes.io/zone

Each domain is one zone. The constraint distributes Pods across zones.

flowchart TB
    subgraph "us-east-1a"
      N1[node-01] --> P1[db-1]
    end
    subgraph "us-east-1b"
      N2[node-02] --> P2[db-2]
    end
    subgraph "us-east-1c"
      N3[node-03] --> P3[db-3]
    end

For a 3-replica Deployment with maxSkew: 1 across 3 zones, each zone gets 1 Pod. A zone failure loses 1 replica.

topology.kubernetes.io/region (per region)

topologySpreadConstraints:
- maxSkew: 1
  topologyKey: topology.kubernetes.io/region

Each domain is one region. Useful for cluster-spanning workloads (rare in production; most clusters are single-region).

Layered constraints

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

Two constraints: one per node (hard) and balanced across zones (soft). The Pod must satisfy both.

flowchart TB
    A[Pod arrives] --> B{Constraint 1:<br/>one per node?}
    B -->|yes| C[Continue]
    B -->|no| D[Pending]
    C --> E{Constraint 2:<br/>balanced zones?}
    E -->|yes| F[Schedule]
    E -->|no| G[Schedule with skew]

The cost

flowchart LR
    A[Topology key] -->|hostname| B["Many domains<br/>fast counting"]
    A -->|zone| C["Few domains<br/>very fast"]
    A -->|region| D["Very few domains<br/>fastest"]
    B --> E[Walk per node]
    C --> F[Walk per zone]
    D --> G[Walk per region]

Hostname walks every node; zone walks every zone (typically 3-5); region walks every region (typically 1-3). The scheduler counts matching Pods per domain. The cost is O(P) where P is the total Pod count (cached).

For a 1000-Pod cluster, the count is a single walk through the cache. Topology spread is cheaper than anti-affinity because the cost is counting, not selector evaluation.

Custom topology keys

topologySpreadConstraints:
- maxSkew: 1
  topologyKey: rack.example.com/rack-id

A custom topology key requires the cluster’s nodes to have the label. The scheduler groups nodes by label value.

kubectl label node node-01 rack.example.com/rack-id=rack-1
kubectl label node node-02 rack.example.com/rack-id=rack-2

Custom topology keys are useful for:

  • Rack-level distribution (data centre topology).
  • Custom hardware tiers (e.g., tier=premium).
  • Software-defined domains (e.g., per-application boundaries).

Verifying the cluster has the labels

# Verify zone labels exist
kubectl get nodes -o custom-columns=NAME:.metadata.name,ZONE:.metadata.labels.topology\.kubernetes\.io/zone
# NAME       ZONE
# node-01    us-east-1a
# node-02    us-east-1b

# Verify hostname labels (always set)
kubectl get nodes -o custom-columns=NAME:.metadata.name,HOSTNAME:.metadata.labels.kubernetes\.io/hostname
# NAME       HOSTNAME
# node-01    node-01
# node-02    node-02

# Verify custom labels
kubectl get nodes -o custom-columns=NAME:.metadata.name,RACK:.metadata.labels.rack\.example\.com/rack-id
# NAME       RACK
# node-01    rack-1
# node-02    rack-2

If the cluster’s nodes do not have the labels, the topology spread constraint has no effect (every node is in the same “missing” domain).

Failure modes

Failure 1: missing zone label

A constraint with topologyKey: topology.kubernetes.io/zone on a cluster where no nodes have the zone label:

flowchart TB
    A[Topology key] --> B{All nodes have<br/>zone label?}
    B -->|no| C["All nodes in same<br/>missing-label domain"]
    B -->|yes| D[Distribution works]
    C --> E[Constraint has no effect]

The fix: add the zone label, or use a topology key that exists.

Failure 2: empty domain

A topology key whose value is empty (""):

kubectl get nodes -o custom-columns=NAME:.metadata.name,ZONE:.metadata.labels.topology\.kubernetes\.io/zone
# NAME       ZONE
# node-01
# node-02

Empty values are treated as the same domain. The distribution is unbalanced. The fix: set the label correctly.

Failure 3: single domain

A topology key with only one domain (e.g., single-zone cluster):

topologySpreadConstraints:
- maxSkew: 1
  topologyKey: topology.kubernetes.io/zone

With one zone, the skew is always 0; the constraint is satisfied trivially. The constraint does not spread across nodes; for that, use kubernetes.io/hostname.

Production patterns

Pattern 1: layered (hostname + zone)

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

One per node, balanced across zones. A node failure loses one Pod; a zone failure loses one per node in the zone.

Pattern 2: hostname only (small cluster)

topologySpreadConstraints:
- maxSkew: 1
  topologyKey: kubernetes.io/hostname
  whenUnsatisfiable: DoNotSchedule
  labelSelector:
    matchLabels:
      app: web

A single-zone cluster. Hostname is the only meaningful domain.

Pattern 3: zone + custom rack

topologySpreadConstraints:
- maxSkew: 1
  topologyKey: topology.kubernetes.io/zone
- maxSkew: 1
  topologyKey: rack.example.com/rack-id

Zone-level balance and rack-level balance. A multi-rack zone distributes Pods across racks; a single-rack zone distributes across the zone’s nodes.

Quiz

Knowledge check · 4 questions

  1. Q1. What is the difference between kubernetes.io/hostname and topology.kubernetes.io/zone as topology keys?

  2. Q2. Topology keys with few domains (e.g., 3 zones) are slower than keys with many domains (e.g., 1000 hostnames).

  3. Q3. Your team uses topology spread with topologyKey topology.kubernetes.io/zone but the cluster has only one zone. The constraint has no effect. Diagnose.

    Topology spread with topologyKey topology.kubernetes.io/zone. Cluster has 10 nodes all in one zone.

  4. Q4. Explain layered topology constraints (hostname + zone) and how they combine.

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Verify the cluster has the labels. A topology key with missing labels has no effect.
  • Layer constraints for layered protection. Hostname
    • zone gives node-level and zone-level distribution.
  • Use ScheduleAnyway for flexibility. A workload that prefers balance but accepts some imbalance uses ScheduleAnyway to avoid Pending Pods.
  • Custom keys require operator setup. A custom topology key is only useful if the cluster’s nodes have the label.
  • Audit the resulting distribution. A dashboard that surfaces per-domain Pod counts catches imbalance.

Topology keys define the placement domain. Operators who choose deliberately have workloads that distribute across the right failure domains.