主题
第 6 章:与亲和性调度的对比与组合
"我到底该用 nodeSelector、nodeAffinity 还是 taint/toleration?"——本章彻底讲清楚。
6.1 三大调度控制机制对比
| 维度 | nodeSelector | nodeAffinity | Taint + Toleration |
|---|---|---|---|
| 配置位置 | Pod | Pod | 节点(taint)+ Pod(toleration) |
| 语义方向 | 吸引:Pod 选择节点 | 吸引:Pod 选择节点 | 排斥:节点拒绝 Pod |
| 表达能力 | 只能等值匹配 | 丰富(In/NotIn/Exists/Gt/Lt、软/硬约束) | key/value/effect 匹配 |
| 软约束(preferred) | ❌ | ✅ | ✅(PreferNoSchedule) |
| 能否驱逐已运行 Pod | ❌ | ❌ | ✅(NoExecute) |
| 防止"别人"的 Pod 上来 | ❌ | ❌ | ✅ |
| 典型用途 | 简单定向 | 复杂定向、拓扑亲和 | 节点隔离、故障驱逐 |
一句话总结:
nodeSelector/nodeAffinity 回答"我的 Pod 想去哪儿";Taint/Toleration 回答"节点允许谁来"。
6.2 nodeSelector vs nodeAffinity
yaml
# nodeSelector:简单等值匹配
spec:
nodeSelector:
disktype: ssdyaml
# nodeAffinity:等价表达 + 更多能力
spec:
affinity:
nodeAffinity:
# 硬约束:调度时必须满足
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In # In / NotIn / Exists / DoesNotExist / Gt / Lt
values: ["ssd", "nvme"]
# 软约束:尽量满足(打分项)
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: zone
operator: In
values: ["cn-hangzhou-a"]命名含义:
requiredDuringSchedulingIgnoredDuringExecution= "调度时必需,运行中忽略"(节点标签变了不会驱逐已运行 Pod)。
6.3 互补关系图解
┌─────────────┐
│ 集群节点 │
└─────────────┘
┌──────────────┼──────────────────┐
▼ ▼ ▼
普通节点 GPU 节点 故障节点
(无污点) (taint: gpu) (taint: NoExecute)
▲ ▲ ▲
│ │ │
谁都能来 只有容忍 gpu 只有容忍该污点
污点的 Pod 能来 的 Pod 能留下
(toleration) (toleration +
tolerationSeconds)经典组合模式(第 5 章场景一的四件套):
节点侧:label(team=team-a) + taint(dedicated=team-a:NoSchedule)
│ │
│ label │ taint
▼ ▼
Pod 侧: nodeAffinity ────────┘ toleration ──┘
(吸引:必须去这批节点) (通行:允许进入这批节点)6.4 决策树:我该用哪个?
需求是"限制哪些 Pod 能调度到某节点"?
│
├── 是 → Taint + Toleration
│ ├─ 硬隔离?→ NoSchedule
│ ├─ 软倾向?→ PreferNoSchedule
│ └─ 还要赶走已有 Pod?→ NoExecute
│
└── 否,只是"我的 Pod 想去特定节点"?
│
├─ 简单的 key=value 匹配 → nodeSelector
└─ 复杂条件 / 需要软约束 → nodeAffinity
├─ 必须满足 → required...
└─ 尽量满足 → preferred...常见问题澄清:
Q1:Pod 配了 toleration 但没配 affinity,会怎样? 能进被污点的节点,但也可能调度到普通节点——容忍只是"允许",不是"必须"。
Q2:只用 nodeAffinity 不配 toleration,Pod 能进有污点的节点吗? 不能。affinity 通过过滤阶段时,污点检查依然会拒绝它。两者是先后两道独立的关卡。
Q3:能只用 taint 不用 label 做专用节点吗? 不能定向。taint 只能"挡",不能"引"——A 团队的 Pod 可能跑到普通节点上,和普通业务抢资源。
6.5 调度规则全景图
一个 Pod 调度到某节点,要同时通过以下所有检查(过滤阶段):
Pod ──▶ ① 资源是否足够(requests)
──▶ ② nodeSelector 是否匹配
──▶ ③ required nodeAffinity 是否满足
──▶ ④ 节点污点是否全被容忍 ← 本章主题
──▶ ⑤ Pod 亲和/反亲和规则
──▶ ⑥ 卷/端口/拓扑约束
──▶ ⑦ 打分排序(preferred 规则在此加分)
──▶ 选定节点任何一关不过,事件里都会报相应的 FailedScheduling 原因(第 7 章会用到)。
6.6 组合案例:生产级 GPU 推理服务
需求:推理服务必须跑在 A100 GPU 节点;GPU 节点不跑其他任何 Pod;尽量分散到不同可用区。
bash
kubectl label nodes gpu-{1,2,3} accelerator=a100
kubectl taint nodes gpu-{1,2,3} nvidia.com/gpu=true:NoScheduleyaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: inference
spec:
replicas: 6
selector:
matchLabels:
app: inference
template:
metadata:
labels:
app: inference
spec:
affinity:
nodeAffinity: # 吸引:必须去 A100 节点
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: accelerator
operator: In
values: ["a100"]
podAntiAffinity: # 分散:尽量不要扎堆
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: inference
topologyKey: topology.kubernetes.io/zone
tolerations: # 通行:容忍 GPU 污点
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: server
image: inference-server:v2
resources:
limits:
nvidia.com/gpu: 1四层机制各司其职:
| 机制 | 职责 |
|---|---|
| nodeAffinity (required) | 必须落在 A100 节点 |
| toleration | 允许穿过 GPU 节点的污点 |
| taint | 挡住其他业务 Pod,保护 GPU 节点 |
| podAntiAffinity (preferred) | 跨可用区分散,提升容灾 |
本章小结
- Taint/Toleration 管"排斥",nodeSelector/nodeAffinity 管"吸引",互不替代、经常组合。
- 专用节点标准配方:节点 label + taint;Pod affinity + toleration。
- 过滤阶段所有约束都要过;preferred 规则只在打分阶段生效。
- 生产方案通常是多种调度机制的叠加,设计时逐层问"谁负责挡、谁负责引、谁负责散"。
思考题
- 节点只有 label 没有 taint,其他 Pod 配了 affinity 但没配 toleration,能调度上去吗?
- 如果希望"Pod 尽量去高配节点、但也不拒绝普通节点",应该用哪种机制?
requiredDuringSchedulingIgnoredDuringExecution中 IgnoredDuringExecution 意味着什么?