Skip to content

第 6 章:与亲和性调度的对比与组合

"我到底该用 nodeSelector、nodeAffinity 还是 taint/toleration?"——本章彻底讲清楚。

6.1 三大调度控制机制对比

维度nodeSelectornodeAffinityTaint + Toleration
配置位置PodPod节点(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: ssd
yaml
# 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:NoSchedule
yaml
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 规则只在打分阶段生效。
  • 生产方案通常是多种调度机制的叠加,设计时逐层问"谁负责挡、谁负责引、谁负责散"。

思考题

  1. 节点只有 label 没有 taint,其他 Pod 配了 affinity 但没配 toleration,能调度上去吗?
  2. 如果希望"Pod 尽量去高配节点、但也不拒绝普通节点",应该用哪种机制?
  3. requiredDuringSchedulingIgnoredDuringExecution 中 IgnoredDuringExecution 意味着什么?