KubernetesXXIII · nodeSelector and Node AffinityNode affinity
preferredDuringSchedulingIgnoredDuringExecution — soft node affinity
What you'll learn
- Configure preferredDuringSchedulingIgnoredDuringExecution node affinity
- Reason about the weight (1-100) and its effect on scoring
- Distinguish preferred from required affinity in failure modes
- Apply preferred affinity to common production patterns
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
preferredDuringSchedulingIgnoredDuringExecution is the
soft-constraint variant of Node Affinity. Instead of
eliminating nodes that don’t match, it adds weight to the
score. If no node matches the preference, the Pod still
schedules on any feasible node. This lesson covers the
syntax, the weight semantics, and when to reach for
preferred vs required affinity.
The syntax
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: disk
operator: In
values: ["ssd"]
- weight: 20
preference:
matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values: ["us-east-1a"]
A list of preferences, each with a weight (1-100) and a
preference (matchExpressions). The weights are added to
the score for nodes that match.
flowchart LR
A[Feasible nodes] --> B[Score phase]
B --> C{Node matches<br/>preference?}
C -->|yes| D["Score += weight"]
C -->|no| E[Score unchanged]
D --> F[Final score]
E --> F
The weight
The weight is a relative score added to the node’s total:
flowchart TB
A["Node X<br/>matches preference 1 (weight 80)"] --> B["Score: 80"]
A2["Node Y<br/>does not match"] --> B2["Score: 0"]
A3["Node Z<br/>matches preference 2 (weight 20)"] --> B3["Score: 20"]
A --> C[Other scoring plugins]
A2 --> C
A3 --> C
C --> D["Final score: 80 + other"]
B2 --> E["Final score: 0 + other"]
B3 --> F["Final score: 20 + other"]
A higher weight means a stronger preference. With
weight: 100 and a node that matches, the node’s score
gets a 100-point bonus (out of the maximum 100). With
weight: 50, the bonus is 50 points.
Weights are relative, not absolute. A weight: 50 does not
mean “50% chance of selection”; it means “50 points added
to the score.”
Preferred affinity never blocks
flowchart TB
A["Pod with preferred<br/>node affinity"] --> B[Filter phase]
B --> C{All feasible nodes<br/>fail preferences?}
C -->|yes| D[No bonus added]
C -->|no| E["Matching nodes get<br/>weight bonus"]
D --> F["Pod still schedules<br/>on any feasible node"]
E --> G["Higher-scoring node<br/>wins"]
Unlike required affinity, preferred affinity does not eliminate nodes. If the preference is unsatisfiable, the Pod schedules on any feasible node — possibly with no preference applied.
Combining preferred and required
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: disk
operator: In
values: ["ssd"]
The required constraint is arch=amd64 (the Pod must land
on an amd64 node). The preferred constraint is disk=ssd
(the Pod prefers SSD but is fine with HDD if no SSD is
available).
flowchart TB
A[Filter phase] --> B{Required: arch=amd64}
B -->|matches| C["Feasible: amd64 nodes"]
B -->|no match| D[Pending]
C --> E[Score phase]
E --> F{Preferred: disk=ssd?}
F -->|yes| G["Score += 100"]
F -->|no| H[Score unchanged]
G --> I[Highest score wins]
H --> I
When to use which
flowchart TB
A{Is the constraint<br/>hard or soft?}
A -->|hard: must satisfy| B[required]
A -->|soft: prefer but allow fallback| C[preferred]
B --> D["Pod may be unschedulable<br/>if no node matches"]
C --> E["Pod always schedules<br/>on any feasible node"]
| Use required when… | Use preferred when… |
|---|---|
| The workload cannot run anywhere else | The workload prefers certain nodes but works elsewhere |
| Compliance / regulatory pinning | Latency, performance, or cost optimisation |
| Hardware-specific (GPU) | Cost-aware placement (prefer cheaper nodes) |
| Failure mode: Pending Pod | Failure mode: suboptimal placement |
Production patterns
Pattern 1: prefer SSD
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: disk
operator: In
values: ["ssd"]
The workload prefers SSD but runs on HDD if no SSD is available. The weight (80) makes the preference strong but not absolute.
Pattern 2: prefer local zone
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values: ["us-east-1a"]
The workload prefers zone us-east-1a for latency. Other
zones are fine if us-east-1a is unavailable.
Pattern 3: avoid spot instances
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: node.kubernetes.io/lifecycle
operator: NotIn
values: ["spot"]
The workload prefers on-demand nodes but can run on spot if no on-demand is available.
Pattern 4: combine multiple preferences
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 50
preference:
matchExpressions:
- key: disk
operator: In
values: ["ssd"]
- weight: 30
preference:
matchExpressions:
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- weight: 20
preference:
matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values: ["us-east-1a"]
Three preferences with different weights. A node that matches all three gets a 100-point bonus; a node that matches none gets 0.
Failure modes
Failure 1: weight too low to matter
A weight: 1 is rarely significant in the total score;
the scheduler’s other plugins dominate. The preference is
effectively no-op.
The fix: increase the weight (50-100 is meaningful) or ensure the scheduler profile uses the Node Affinity plugin.
Failure 2: preference unsatisfiable
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: disk
operator: In
values: ["ssd"]
If no node has disk=ssd, the Pod schedules anywhere.
The preference is silent. Verify the cluster’s labels
when the workload is consistently placed on HDD nodes.
Failure 3: required inside preferred
# WRONG: required is not valid in preferred
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: disk
operator: In
values: ["ssd"]
required: true # not valid here
The required field is for nodeSelector inside
nodeSelectorTerms; it does not belong in preferred.
Quiz
Knowledge check · 4 questions
Q1. What does preferredDuringSchedulingIgnoredDuringExecution do?
Q2. A preferredDuringSchedulingIgnoredDuringExecution rule with weight 1 is always meaningful because the scheduler's other plugins have lower weights.
Q3. Your team's web Pods have preferred affinity for SSD nodes with weight 100. The Pods land on HDD nodes. Diagnose.
Web Pods with preferredDuringSchedulingIgnoredDuringExecution for disk ssd weight 100. Cluster has 4 SSD nodes (all utilised) and 4 HDD nodes (free).
Q4. When should you use preferred node affinity versus required node affinity?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Use preferred for performance/cost optimisations. A weight of 50-100 with a clear preference is the right shape.
- Use required for compliance and hardware pinning. A hard constraint with no fallback is the correct shape.
- Combine preferred and required. A workload can have both: hard on architecture, soft on disk.
- Verify the weights. A
weight: 1is too low to matter; verify the weight is meaningful (50+) for the preference to have effect. - Audit the resulting placement. A dashboard that surfaces the cluster’s node distribution per workload catches preference malfunctions.
Preferred node affinity is the right tool for soft constraints. Operators who choose deliberately have workloads that land predictably.