What is Node Affinity in Kubernetes? Pod Scheduling Explained Simply
Node affinity lets you control which nodes your pods run on. Here's a plain-English explanation of nodeSelector, nodeAffinity, podAffinity, and taints/tolerations — when to use each.
By default, Kubernetes schedules pods on any available node. Sometimes that's not what you want. Your GPU workloads should run on GPU nodes. Your database shouldn't share a node with untrusted workloads.
Node affinity is how you control this.
The Simple Version First: nodeSelector
The simplest way to pin a pod to specific nodes — requires a matching label on the node.
# Step 1: Label your node
kubectl label node node-1 disk=ssd
# Step 2: Tell your pod to only run on SSD nodes
apiVersion: v1
kind: Pod
spec:
nodeSelector:
disk: ssd
containers:
- name: my-app
image: my-app:latestIf no node has disk=ssd, the pod stays Pending. Simple and works well for most cases.
Node Affinity — More Expressive Rules
Node affinity gives you more control than nodeSelector. You can define required rules and preferred rules.
Required (Hard Constraint)
Pod will NOT schedule unless this is satisfied:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
- arm64This pod only runs on amd64 or arm64 nodes.
Preferred (Soft Constraint)
Kubernetes tries to place pod here, but places it elsewhere if no match:
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80 # Higher weight = stronger preference
preference:
matchExpressions:
- key: node-type
operator: In
values:
- spot
- weight: 20
preference:
matchExpressions:
- key: node-type
operator: In
values:
- on-demandThis pod prefers spot instances but falls back to on-demand if no spot is available.
Operators in Node Affinity
| Operator | Meaning | Example |
|---|---|---|
In | Value in list | zone In [us-east-1a, us-east-1b] |
NotIn | Value NOT in list | env NotIn [test, dev] |
Exists | Label exists (any value) | gpu Exists |
DoesNotExist | Label absent | spot DoesNotExist |
Gt | Greater than | cpus Gt 4 |
Lt | Less than | memory Lt 16 |
Real-World Examples
Run GPU workloads on GPU nodes only
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: nvidia.com/gpu
operator: Exists
containers:
- name: ml-training
image: pytorch:latest
resources:
limits:
nvidia.com/gpu: "1"Prefer spot instances, tolerate on-demand
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: eks.amazonaws.com/capacityType
operator: In
values: [SPOT]Spread across availability zones
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- ap-south-1a
- ap-south-1b
- ap-south-1cPod Affinity and Anti-Affinity
Node affinity = "schedule on this type of node."
Pod affinity = "schedule near/away from this type of pod."
Co-locate pods on the same node (affinity)
Cache pods should be on the same node as app pods (lower latency):
spec:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: redis-cache
topologyKey: kubernetes.io/hostname # "same node"Spread pods across nodes (anti-affinity)
Don't run two replicas of the same app on the same node:
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: my-api
topologyKey: kubernetes.io/hostname # Different node
# Or spread across AZs:
- labelSelector:
matchLabels:
app: my-api
topologyKey: topology.kubernetes.io/zone # Different AZTaints and Tolerations (The Opposite Direction)
Node affinity is "pods choosing nodes." Taints/tolerations is "nodes repelling pods."
# Taint a node — only pods that tolerate this can schedule here
kubectl taint nodes node-1 gpu=true:NoSchedule
# Remove taint
kubectl taint nodes node-1 gpu=true:NoSchedule-# Pod must have this toleration to schedule on tainted node
spec:
tolerations:
- key: gpu
operator: Equal
value: "true"
effect: NoScheduleTaint effects:
NoSchedule— New pods without toleration won't schedule herePreferNoSchedule— Soft version — tries to avoid, but schedules if necessaryNoExecute— Existing pods without toleration are evicted
When to Use What
| Scenario | Solution |
|---|---|
| Run only on SSD nodes | nodeSelector or nodeAffinity |
| Prefer spot instances | nodeAffinity preferred |
| Dedicated GPU nodes | Taint GPU nodes + toleration in pod |
| HA across AZs | podAntiAffinity with zone topologyKey |
| Cache near app | podAffinity with hostname topologyKey |
| Isolate untrusted workloads | Taint + toleration |
Topology Spread Constraints (Modern Alternative)
For spreading pods across nodes/zones without complex affinity rules:
spec:
topologySpreadConstraints:
- maxSkew: 1 # Max difference between zones
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: my-apiThis is the recommended modern way to spread pods across AZs — simpler than pod anti-affinity.
Node affinity sounds complex but boils down to: "I want this pod to run on nodes that have these labels." Once you understand that, the rest is just syntax.
For CKA exam prep and Kubernetes scheduling deep dives, KodeKloud has hands-on labs covering affinity, taints, tolerations, and topology spread constraints.
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
Build a Kubernetes Cluster with kubeadm from Scratch (2026)
Step-by-step guide to building a real multi-node Kubernetes cluster using kubeadm — no managed services, no shortcuts.
How to Build a DevOps Home Lab for Free in 2026
You don't need expensive hardware to practice DevOps. Here's how to build a complete home lab with Kubernetes, CI/CD, and monitoring using free tools and cloud free tiers.
How to Crack the CKA Exam in 2026: Study Plan, Resources, and Tips
Complete CKA exam prep guide for 2026 — what to study, how to practice, which resources actually help, and tips to pass on the first attempt.