Affinity
A Kubernetes scheduling rule that expresses attraction constraints — directing the scheduler to prefer or require that pods land on specific nodes or near specific other pods. Comes in two forms: Node Affinity (pod-to-node preferences) and Pod Affinity/Anti-Affinity (pod-to-pod co-location or separation rules).
Affinity — Telling the Scheduler Where Your Pods Belong
The Full Picture: Taints vs Affinity
These two mechanisms are often confused because they both influence scheduling. Here is the distinction:
| Taints (on Nodes) | Affinity (on Pods) |
|---|---|
| Node says: "Stay away unless you tolerate me" | Pod says: "I want to be near X" or "I must be on Y" |
| Push-based repulsion | Pull-based attraction |
They work together. Taints keep unwanted pods off nodes. Affinity rules pull the right pods to the right nodes.
Node Affinity — Pod Wants a Specific Node Type
Use case: Zerodha's market-data processing pods need GPU nodes. Regular pods should not land there.
spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: # HARD rule — must match nodeSelectorTerms: - matchExpressions: - key: node.kubernetes.io/instance-type operator: In values: - p3.2xlarge # GPU instance type - p3.8xlarge preferredDuringSchedulingIgnoredDuringExecution: # SOFT rule — try to match - weight: 80 # 0-100, higher = stronger preference preference: matchExpressions: - key: topology.kubernetes.io/zone operator: In values: - ap-south-1a # Prefer Mumbai AZ-AThe two scheduling modes:
| Mode | Behavior |
|---|---|
requiredDuringSchedulingIgnoredDuringExecution |
Pod will NOT schedule if no matching node found (hard requirement) |
preferredDuringSchedulingIgnoredDuringExecution |
Pod tries to schedule on matching node, but falls back if none available |
RememberThe
IgnoredDuringExecutionpart means if a node's labels change after a pod is already running, the pod is NOT evicted. The rule only applies at scheduling time.
Pod Anti-Affinity — Spread Pods Across Nodes/Zones
Use case: Swiggy's order-service runs 6 replicas. If all 6 land on one node and that node dies, the entire service goes down. Anti-affinity forces the scheduler to spread them out.
spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: order-service # Don't place me near other order-service pods topologyKey: kubernetes.io/hostname # "near" means "on the same node"This guarantees no two order-service pods share a node. For zone-level HA, change topologyKey to topology.kubernetes.io/zone.
Pod Affinity — Keep Pods Together
Use case: A data-processing pod and its Redis sidecar should always land on the same node to minimize latency.
spec: affinity: podAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: redis-cache topologyKey: kubernetes.io/hostname # "with" means "on the same node"Quick Decision Tree
+------------------------------------------------------+| Do you need to control where a pod lands? |+------------------------------------------------------+ | | v v+---------------------+ +------------------------+| Based on node | | Based on other pods? || hardware/labels? | +------------------------+| -> Node Affinity | | |+---------------------+ v v | +------------+ +------------+ v | Stay AWAY | | Stay NEAR | +-------+-------+ | from pods | | a pod | | | | -> Anti- | | -> Pod | v v | Affinity | | Affinity |+--------+ +---------+ +------------+ +------------+| Hard | | Soft | | Spread replicas across || must | | prefer | | nodes/zones for HA || land | | to land | +----------------------------+| required preferred |+--------+ +---------+Common MistakeUsing
requiredanti-affinity with more replicas than nodes. If you have 3 nodes and 4 replicas withrequiredanti-affinity, the 4th pod will be stuck inPendingforever — there is no node without an existing pod to satisfy the constraint. Usepreferredunless you are certain about your node count.
Frequently Asked Questions
What's the practical difference between affinity and a nodeSelector?
nodeSelector is a simple equality match on node labels — a pod either lands on a matching node or stays Pending. Affinity supports much richer logic: preferred (soft, best-effort) versus required (hard) rules, set-based operators like In/NotIn, and — uniquely — pod-to-pod rules, letting you co-locate pods that talk to each other frequently or spread replicas across failure domains for resilience.
What's a common gotcha with affinity rules?
Overusing requiredDuringSchedulingIgnoredDuringExecution constraints can leave pods stuck Pending when no node satisfies every rule simultaneously, especially during a rolling update when capacity is temporarily tight. Most teams default to preferred rules for anti-affinity (spread replicas across zones/nodes when possible) and reserve required rules for genuine hard constraints, like GPU-only workloads. Debugging a stuck pod starts with kubectl describe pod, whose Events section names the exact rule that blocked scheduling.