Skip to content

How to Configure Kubernetes Pod Anti-Affinity

DodaTech Updated 2026-06-24 3 min read

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

The Problem

Your application pods are all scheduled on the same node despite using anti-affinity. When that node fails, all replicas go down simultaneously. The anti-affinity rule either does not prevent co-location or prevents scheduling entirely.

Quick Fix

Fix 1: Preferred vs Required Anti-Affinity

WRONG — using preferredDuringSchedulingIgnoredDuringExecution expecting hard enforcement:

spec:
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              app: my-app
          topologyKey: kubernetes.io/hostname
# (pods can still be scheduled on the same node if no other node has capacity)

RIGHT — use requiredDuringSchedulingIgnoredDuringExecution for hard enforcement:

spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            app: my-app
        topologyKey: kubernetes.io/hostname

Now the scheduler ensures no two pods with app: my-app are on the same node.

Fix 2: Topology Key Must Match Node Labels

WRONG — using a topology key that does not exist on nodes:

topologyKey: failure-domain.beta.kubernetes.io/zone
# (this label may not exist on all clusters — use kubernetes.io/hostname for immediate effect)

RIGHT — use standard topology keys:

# Node-level: try to spread across hosts
topologyKey: kubernetes.io/hostname

# Zone-level: try to spread across availability zones
topologyKey: topology.kubernetes.io/zone

# Region-level: try to spread across regions
topologyKey: topology.kubernetes.io/region

Fix 3: Label Selector Scope

WRONG — matching labels that do not exist:

labelSelector:
  matchLabels:
    app: my-app    # must match the labels on the pods being deployed

RIGHT — ensure labels match:

# Deployment metadata:
metadata:
  labels:
    app: my-app

# Anti-affinity selector:
labelSelector:
  matchLabels:
    app: my-app    # matches the deployment's pod labels

Fix 4: Insufficient Nodes

# 3 replicas with required anti-affinity, but only 2 nodes
# One pod stays Pending: "0/2 nodes are available: 2 node(s) didn't match pod anti-affinity rules"

RIGHT — use preferred instead of required:

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 100
      podAffinityTerm:
        labelSelector:
          matchLabels:
            app: my-app
        topologyKey: kubernetes.io/hostname

Or scale up the node pool.

Fix 5: Pod Anti-Affinity with Different Topologies

To spread pods across zones first, then hosts:

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 50
      podAffinityTerm:
        topologyKey: topology.kubernetes.io/zone
        labelSelector:
          matchLabels:
            app: my-app
    - weight: 100
      podAffinityTerm:
        topologyKey: kubernetes.io/hostname
        labelSelector:
          matchLabels:
            app: my-app

Fix 6: Namespace Scope

# Anti-affinity across namespaces:
labelSelector:
  matchLabels:
    app: my-app
namespaces: ["ns1", "ns2"]
# (by default, only the same namespace is considered)

Use DodaTech's Scheduler Simulator to visualize pod placement with anti-affinity rules and predict behavior before deploying.

Prevention

  • Use requiredDuringScheduling for critical workload separation.
  • Always verify topology keys exist on your nodes.
  • Scale node pools to accommodate anti-affinity constraints.
  • Use preferred for bursting scenarios.
  • Test anti-affinity with kubectl get pods -o wide to verify distribution.

Common Mistakes with pod anti affinity

  1. Mixing let bindings with <- bindings in do notation, producing type errors
  2. Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
  3. Non-exhaustive pattern matches that compile with warnings then crash at runtime

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

### Why is my pod stuck Pending with anti-affinity rules?

There are not enough nodes that satisfy the anti-affinity constraints. If you have 3 replicas with requiredDuringScheduling and only 2 nodes, one pod stays Pending. Switch to preferredDuringScheduling or add more nodes.

What is the difference between podAntiAffinity and podAffinity?

podAntiAffinity tries to keep pods apart (spread across nodes). podAffinity tries to place pods together (co-locate on the same node). Both use the same topologyKey mechanism with label selectors.

How does anti-affinity work with rolling updates?

During rolling updates, the new pod must satisfy anti-affinity with existing pods. If the only node with capacity already runs a replica, the update may hang. Use maxSurge: 1 and maxUnavailable: 0 to control the rollout pace.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro