K8s by Example: Pod Affinity

Pod affinity schedules Pods on nodes where specific Pods are already running. Use for: co-locating related services, reducing network latency, data locality.

pod-affinity.yaml

Pod affinity is defined in spec.affinity.podAffinity. labelSelector matches target Pods. topologyKey defines the scope (same node, zone, etc.).

spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchLabels:
              app: cache
          topologyKey: kubernetes.io/hostname
pod-affinity-types.yaml

First example: required is a hard constraint, so the Pod won’t schedule if unsatisfied. Second example: preferred is soft, so the scheduler tries but doesn’t guarantee. Weight determines preference strength (higher = stronger).

spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchLabels:
              app: cache
          topologyKey: kubernetes.io/hostname
---
spec:
  affinity:
    podAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 100
          podAffinityTerm:
            labelSelector:
              matchLabels:
                app: cache
            topologyKey: kubernetes.io/hostname
topology-keys.yaml

topologyKey defines the scope. kubernetes.io/hostname = same node, topology.kubernetes.io/zone = same AZ, topology.kubernetes.io/region = same region. Custom keys for rack-aware scheduling.

topologyKey: kubernetes.io/hostname

topologyKey: topology.kubernetes.io/zone

topologyKey: topology.kubernetes.io/region

topologyKey: rack.example.com/rack-id
pod-affinity-expressions.yaml

Use matchExpressions for complex label matching. Supports operators: In, NotIn, Exists, DoesNotExist. Multiple expressions use AND logic.

podAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
        matchExpressions:
          - key: app
            operator: In
            values:
              - cache
              - queue
          - key: environment
            operator: In
            values:
              - production
      topologyKey: kubernetes.io/hostname
pod-affinity-namespace.yaml

namespaceSelector matches Pods across namespaces. By default, affinity only considers Pods in the same namespace. Use for cross-namespace dependencies.

podAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
        matchLabels:
          app: cache
      namespaceSelector:
        matchLabels:
          team: platform
      topologyKey: kubernetes.io/hostname
---
    - labelSelector:
        matchLabels:
          app: cache
      namespaces:
        - shared-services
      topologyKey: kubernetes.io/hostname
pod-combined-affinity.yaml

Combine affinity with anti-affinity for complex placement. Co-locate with dependencies but spread across nodes. Common pattern for stateful applications with their caches.

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

Debug pod affinity issues by checking scheduler events. Pending Pods show why no node was selected. Verify target Pods exist and have matching labels.

$ kubectl describe pod my-app
Events:
  Type     Reason            Age   Message
  Warning  FailedScheduling  10s   0/3 nodes available:
    3 node(s) didn't match pod affinity rules

$ kubectl get pods -l app=cache --show-labels
NAME      READY   STATUS    LABELS
cache-1   1/1     Running   app=cache,env=prod

$ kubectl get pods -l app=cache -o wide
NAME      READY   NODE
cache-1   1/1     node-1

$ kubectl get pod my-app -o jsonpath='{.spec.affinity}' | jq

Index | GitHub | Use arrow keys to navigate |