4. 默认调度器调度策略:节点选择、亲和性与污点容忍

Kubernetes 默认调度器(kube-scheduler)在将 Pod 绑定到合适节点时,会依次评估一系列预选(Predicates)与优选(Priorities)策略。其中,节点选择(NodeSelector)、亲和性与反亲和性(Affinity / Anti-Affinity)、污点与容忍(Taint / Toleration)是控制 Pod 调度位置最核心的三类约束机制。理解它们的优先级、组合效果与性能影响,是进行调度调优和故障排查的基础。

核心原则:NodeSelector 是硬性匹配(必须满足标签键值对);NodeAffinity 提供更灵活的匹配语法(支持 In/NotIn/Exists/Gt/Lt 等操作符);PodAffinity/AntiAffinity 基于已运行 Pod 的标签进行拓扑约束;Taint/Toleration 则从节点角度“排斥”非容忍 Pod。四者共同决定 Pod 的最终调度位置。

4.1 节点选择(NodeSelector)

NodeSelector 是最简单、最直接的节点约束方式。通过在 Pod 的 spec.nodeSelector 字段中定义一组键值对,调度器只会将 Pod 调度到包含全部指定标签的节点上。如果没有任何节点满足所有标签条件,Pod 将处于 Pending 状态。

apiVersion: v1
kind: Pod
metadata:
  name: nginx-selector
spec:
  nodeSelector:
    disktype: ssd          # 节点必须包含 disktype=ssd 标签
    region: us-east-1      # 节点必须包含 region=us-east-1 标签
  containers:
  - name: nginx
    image: nginx:1.25
性能提示:NodeSelector 的匹配是 O(1) 哈希查找,性能极高。但它的表达能力有限——只能做“等于”匹配,不支持集合运算或排除逻辑。当需要更复杂的节点选择时,应使用 NodeAffinity。

4.2 亲和性与反亲和性(Affinity / Anti-Affinity)

亲和性规则分为两类:节点亲和性(NodeAffinity)和 Pod 间亲和性/反亲和性(PodAffinity / PodAntiAffinity)。每种规则又支持 requiredDuringSchedulingIgnoredDuringExecution(硬性要求)和 preferredDuringSchedulingIgnoredDuringExecution(软性偏好)两种模式。

4.2.1 节点亲和性(NodeAffinity)

NodeAffinity 扩展了 NodeSelector 的匹配能力,支持 In、NotIn、Exists、DoesNotExist、Gt、Lt 等操作符。硬性规则不满足时 Pod 无法调度;软性规则不满足时调度器会尝试寻找其他更优节点。

apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-pod
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: topology.kubernetes.io/zone
            operator: In
            values:
            - us-east-1a
            - us-east-1b
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 80
        preference:
          matchExpressions:
          - key: instance-type
            operator: In
            values:
            - c5.large
  containers:
  - name: app
    image: nginx
调度性能影响:NodeAffinity 的 requiredDuringScheduling 在预选阶段执行,每个 Pod 需要遍历所有节点进行标签匹配。当集群节点数超过 5000 且规则复杂时,匹配计算量会显著增加。建议将常用标签提前索引,避免在 matchExpressions 中使用大量 NotIn 或 Gt 操作符。

4.2.2 Pod 间亲和性与反亲和性(PodAffinity / PodAntiAffinity)

PodAffinity 将 Pod 调度到已经运行了特定 Pod 的拓扑域中;PodAntiAffinity 则尽量将 Pod 分散到不同拓扑域。拓扑域通过 topologyKey 定义,例如 kubernetes.io/hostname(节点级别)或 topology.kubernetes.io/zone(可用区级别)。

apiVersion: v1
kind: Pod
metadata:
  name: web-frontend
  labels:
    app: frontend
spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - frontend
        topologyKey: kubernetes.io/hostname
  containers:
  - name: nginx
    image: nginx
关键性能瓶颈:PodAffinity/AntiAffinity 的 requiredDuringScheduling 在预选阶段需要为每个候选节点查询该拓扑域内所有已运行 Pod 的标签。当集群 Pod 数量超过 10,000 时,这一步骤的 API 调用和内存消耗会急剧上升。建议:
• 优先使用 preferredDuringScheduling 替代硬性要求。
• 将 topologyKey 设置为较粗的粒度(如 zone 而非 hostname)。
• 避免在 labelSelector 中使用过于宽泛的匹配条件。
亲和性与反亲和性调度决策流程 Pod 调度请求 节点亲和性 (NodeAffinity) required / preferred + 操作符匹配 Pod 亲和性 (PodAffinity) 与已有 Pod 共置拓扑域 Pod 反亲和性 (PodAntiAffinity) 分散到不同拓扑域 调度决策输出 说明: • 硬性规则 (requiredDuringScheduling) 在预选阶段执行,不满足则 Pod 无法调度。 • 软性规则 (preferredDuringScheduling) 在优选阶段加权评分,影响最终节点排序。

4.3 污点与容忍(Taint / Toleration)

污点(Taint)是节点上的一种“排斥标记”,只有带有对应容忍(Toleration)的 Pod 才能被调度到该节点上。污点有三个核心属性:Key、Value(可选)、Effect。Effect 决定了 Pod 被排斥时的行为:

Effect 类型 行为描述 典型场景
NoSchedule 不满足容忍的 Pod 不会被调度到该节点 将专用 GPU 节点标记为仅允许 AI 工作负载
PreferNoSchedule 调度器尽量不将 Pod 调度到该节点,但不强制 节点即将维护,优先将新 Pod 调度到其他节点
NoExecute 不满足容忍的 Pod 会被立即驱逐(如果已在运行) 节点故障时快速驱逐 Pod,避免服务中断
# 给节点添加污点
kubectl taint nodes node-gpu-1 gpu=true:NoSchedule

# Pod 中定义容忍
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  tolerations:
  - key: "gpu"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"
  containers:
  - name: cuda
    image: nvidia/cuda:12.0
调度性能影响:Taint/Toleration 的匹配在预选阶段进行,每个节点只需检查 Pod 的 tolerations 列表是否覆盖了节点的所有 NoSchedule/NoExecute 污点。由于污点数量通常很少(一般 1-3 个),匹配计算开销极低。但 NoExecute 污点会触发 Pod 驱逐,对集群稳定性影响较大,应谨慎使用。

4.4 四种策略的优先级与组合效果

当 NodeSelector、NodeAffinity、PodAffinity/AntiAffinity、Taint/Toleration 同时存在时,调度器按以下顺序评估:

  1. 预选阶段:先检查 Taint/Toleration(节点是否排斥 Pod),再检查 NodeSelector(标签键值对匹配),然后检查 NodeAffinity 的硬性规则,最后检查 PodAffinity/AntiAffinity 的硬性规则。任一条件不满足则过滤该节点。
  2. 优选阶段:对通过预选的节点,根据 NodeAffinity 的软性规则、PodAffinity 的软性规则、以及其他优选策略(如资源水位、Pod 分布)进行加权评分。
常见调度失败原因:
• NodeSelector 与 NodeAffinity 同时定义时,两者是“与”关系——节点必须同时满足两者条件。
• PodAntiAffinity 的 requiredDuringScheduling 与 Taint 冲突时,即使节点容忍了 Pod,反亲和性仍可能阻止调度。
• 多个 PodAffinity 规则之间是“与”关系,规则越多,可调度节点越少,调度失败概率越高。
四种调度策略组合决策树 候选节点列表 ① Taint/Toleration 检查 ② NodeSelector 标签匹配 ③ NodeAffinity 硬性规则 ④ PodAffinity/AntiAffinity 硬性规则 ⑤ 优选阶段加权评分 最终调度节点 预选阶段按 ①→②→③→④ 顺序过滤,任一失败则跳过该节点;优选阶段对通过节点进行综合评分。

4.5 性能调优建议与排查清单

策略 预选阶段复杂度 调优建议 常见排查点
NodeSelector O(1) 哈希查找 保持标签键值对简洁,避免使用通配符 检查节点标签是否存在、拼写是否正确
NodeAffinity O(n) 遍历 matchExpressions 减少 matchExpressions 条目数,优先使用 In 而非 NotIn 检查 operator 是否支持、values 是否为空
PodAffinity/AntiAffinity O(m * k) m=候选节点数, k=拓扑域内 Pod 数 使用粗粒度 topologyKey,避免 required 硬性规则 检查 labelSelector 是否匹配到目标 Pod、拓扑域是否一致
Taint/Toleration O(t) t=节点污点数 避免添加过多污点,NoExecute 需谨慎使用 检查 tolerationSeconds 是否设置、operator 是否匹配
排查 Pod 调度失败快速命令:
kubectl describe pod <pod-name> — 查看 Events 中的调度失败原因。
kubectl get nodes --show-labels — 确认节点标签是否符合 NodeSelector/NodeAffinity。
kubectl describe node <node-name> | grep Taints — 查看节点污点信息。
kubectl get pods --all-namespaces -o wide | grep <app-label> — 检查 Pod 亲和性依赖的 Pod 是否正常运行。