CKA — Node Affinity

4 minute read

CKA Exam Domain

Domain Weight
Workloads & Scheduling 15%

Node affinity questions on the CKA exam often require you to write YAML from scratch. Memorize the structure — it’s verbose but predictable.

What Is Node Affinity?

Node affinity is the advanced version of nodeSelector. It gives you expressive rules for placing Pods on nodes using set-based operators, soft preferences, and complex logic.

Node affinity lives under .spec.affinity.nodeAffinity and supports two scheduling modes:

Mode Behavior
requiredDuringSchedulingIgnoredDuringExecution Hard — Pod won’t schedule if no node matches
preferredDuringSchedulingIgnoredDuringExecution Soft — Scheduler tries to match, but falls back if needed

The IgnoredDuringExecution part means that if a node’s labels change after the Pod is running, the Pod is not evicted.

requiredDuringSchedulingIgnoredDuringExecution

This is a hard requirement. The Pod will stay Pending if no node satisfies the rule.

apiVersion: v1
kind: Pod
metadata:
  name: affinity-required
spec:
  containers:
    - name: nginx
      image: nginx:1.27
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: disktype
                operator: In
                values:
                  - ssd
                  - nvme

This Pod will only schedule on nodes where disktype is ssd or nvme.

kubectl apply -f affinity-required.yaml
kubectl get pod affinity-required -o wide

preferredDuringSchedulingIgnoredDuringExecution

This is a soft preference. The scheduler will try to honor it, but if no matching node is available, the Pod is scheduled elsewhere.

apiVersion: v1
kind: Pod
metadata:
  name: affinity-preferred
spec:
  containers:
    - name: nginx
      image: nginx:1.27
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 80
          preference:
            matchExpressions:
              - key: zone
                operator: In
                values:
                  - us-east-1a
        - weight: 20
          preference:
            matchExpressions:
              - key: zone
                operator: In
                values:
                  - us-east-1b

The weight field (1–100) tells the scheduler how strongly to prefer each rule. Higher weight = stronger preference. Here, us-east-1a is strongly preferred over us-east-1b.

Affinity Operators

Operator Description Example
In Label value is in the given set values: [ssd, nvme]
NotIn Label value is not in the given set values: [hdd]
Exists Label key exists (value doesn’t matter) key: gpu
DoesNotExist Label key does not exist key: gpu
Gt Label value is greater than (numeric) values: ["4"]
Lt Label value is less than (numeric) values: ["8"]

Exam Tip: Gt and Lt compare the label value as an integer. The value must still be specified as a string in YAML.

Multiple Match Expressions

Understanding AND vs OR logic is critical:

  • Multiple matchExpressions within the same nodeSelectorTerms entry → AND (all must match)
  • Multiple nodeSelectorTerms entries → OR (any one can match)

AND example — node must have both labels:

nodeSelectorTerms:
  - matchExpressions:
      - key: disktype
        operator: In
        values: ["ssd"]
      - key: zone
        operator: In
        values: ["us-east-1a"]

OR example — node must match either term:

nodeSelectorTerms:
  - matchExpressions:
      - key: disktype
        operator: In
        values: ["ssd"]
  - matchExpressions:
      - key: zone
        operator: In
        values: ["us-east-1a"]

Pod Affinity and Anti-Affinity

While node affinity matches Pods to nodes, Pod affinity and anti-affinity match Pods to other Pods using topologyKey.

Pod Affinity — Co-locate Pods

Schedule a Pod on the same node (or zone) as another Pod:

apiVersion: v1
kind: Pod
metadata:
  name: web-frontend
spec:
  containers:
    - name: nginx
      image: nginx:1.27
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
              - key: app
                operator: In
                values:
                  - cache
          topologyKey: kubernetes.io/hostname

This Pod will only be scheduled on a node that already runs a Pod with app=cache.

Pod Anti-Affinity — Spread Pods Apart

Prevent Pods from landing on the same node:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                      - web
              topologyKey: kubernetes.io/hostname

Each replica lands on a different node. This is a common pattern for high availability.

topologyKey defines the scope: kubernetes.io/hostname = same node, topology.kubernetes.io/zone = same zone.

nodeSelector vs Node Affinity

Feature nodeSelector Node Affinity
Syntax Simple key-value Verbose YAML under .spec.affinity
Match type Exact match only Set-based operators
Soft preference Not supported preferredDuringScheduling
OR logic Not supported Multiple nodeSelectorTerms
Complexity Low Medium
CKA frequency Common Very common

kubectl Commands

# Label a node for affinity matching
kubectl label nodes <node-name> <key>=<value>

# Check Pod scheduling
kubectl get pod <pod-name> -o wide

# Describe Pod to see affinity rules and events
kubectl describe pod <pod-name>

# View node labels
kubectl get nodes --show-labels

# Dry-run to generate Pod YAML
kubectl run affinity-test --image=nginx --dry-run=client -o yaml > pod.yaml

Practice Questions

Q1. Create a Pod with a hard node affinity rule that schedules only on nodes with zone set to us-east-1a or us-west-2a.

Show Answer
apiVersion: v1
kind: Pod
metadata:
  name: zone-pod
spec:
  containers:
    - name: nginx
      image: nginx:1.27
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: zone
                operator: In
                values:
                  - us-east-1a
                  - us-west-2a

Q2. Write a soft affinity rule that prefers nodes with tier=frontend (weight 70) but falls back to any node.

Show Answer
affinity:
  nodeAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 70
        preference:
          matchExpressions:
            - key: tier
              operator: In
              values:
                - frontend

Q3. What is the difference between multiple matchExpressions in one nodeSelectorTerms entry vs multiple nodeSelectorTerms entries?

Show Answer
  • Multiple matchExpressions in one nodeSelectorTerms entry = AND (all must match).
  • Multiple nodeSelectorTerms entries = OR (any one must match).

Q4. Create a Deployment with 3 replicas that uses pod anti-affinity to ensure each replica runs on a different node.

Show Answer
apiVersion: apps/v1
kind: Deployment
metadata:
  name: spread-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: spread
  template:
    metadata:
      labels:
        app: spread
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                      - spread
              topologyKey: kubernetes.io/hostname

Q5. A Pod has requiredDuringSchedulingIgnoredDuringExecution with disktype In [ssd]. After the Pod is running, you remove the disktype label from the node. What happens?

Show Answer

Nothing. The IgnoredDuringExecution part means the Pod is not evicted if node labels change after scheduling. The Pod continues to run.

Updated: