3、节点亲和性(nodeAffinity):requiredDuringSchedulingIgnoredDuringExecution 与 preferredDuringSchedulingIgnoredDuringExecution 详解

节点亲和性是 Kubernetes 调度器将 Pod 绑定到特定节点集合的核心策略之一。与简单的 nodeSelector 精确匹配不同,nodeAffinity 提供了丰富的表达式匹配能力,支持硬性约束和软性偏好两种语义,分别对应 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution 规则。

3.1 两种调度语义对比

特性 requiredDuringSchedulingIgnoredDuringExecution preferredDuringSchedulingIgnoredDuringExecution
语义类型 硬性约束(Hard Constraint) 软性偏好(Soft Preference)
调度行为 必须满足所有匹配规则,否则 Pod 无法调度 尽量满足,若不满足则调度到其他可用节点
权重支持 不支持权重,规则必须全部满足 支持权重(weight 1-100),权重越高优先级越大
执行阶段 仅在调度时检查(Scheduling) 仅在调度时评分(Scheduling)
运行时忽略 节点标签变更后,已运行 Pod 不受影响(IgnoredDuringExecution) 节点标签变更后,已运行 Pod 不受影响(IgnoredDuringExecution)
典型场景 GPU 节点、合规节点、专用硬件节点 可用区均衡、机型偏好、成本优化
关键理解:两种规则的 "IgnoredDuringExecution" 后缀意味着:一旦 Pod 成功运行在某个节点上,即使该节点的标签后续发生变化导致不再匹配亲和性规则,Kubernetes 也不会主动驱逐该 Pod。这种设计保证了运行时的稳定性,避免因标签变更引发大规模 Pod 迁移。

3.2 requiredDuringSchedulingIgnoredDuringExecution 硬性约束

该规则使用 matchExpressions 定义一组条件,调度器必须全部满足才能将 Pod 绑定到节点。支持的操作符包括 In、NotIn、Exists、DoesNotExist。

apiVersion: v1
kind: Pod
metadata:
  name: gpu-inference-pod
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: accelerator
            operator: In
            values:
            - nvidia-tesla-v100
            - nvidia-a100
          - key: node-type
            operator: In
            values:
            - gpu-worker
  containers:
  - name: inference
    image: nvidia/cuda:12.0-base

调度逻辑说明:

  • nodeSelectorTerms 列表中的多个条目是或(OR)关系,满足任意一个条目即可。
  • 每个条目内的 matchExpressions 列表是与(AND)关系,必须全部满足。
  • 上例中 Pod 只能调度到同时满足 accelerator In (nvidia-tesla-v100, nvidia-a100) 和 node-type In (gpu-worker) 的节点。

3.3 preferredDuringSchedulingIgnoredDuringExecution 软性偏好

该规则通过 preference 和 weight 定义一组偏好条件。调度器会为每个候选节点计算加权得分,得分最高的节点优先被选中。若没有节点满足偏好,Pod 仍可调度到其他节点。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 5
  template:
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80
            preference:
              matchExpressions:
              - key: topology.kubernetes.io/zone
                operator: In
                values:
                - us-east-1a
          - weight: 20
            preference:
              matchExpressions:
              - key: instance-type
                operator: In
                values:
                - c5.large
      containers:
      - name: nginx
        image: nginx:1.25

评分机制说明:

  • 每个偏好规则独立计算,满足则累加对应权重,不满足则加 0。
  • 上例中,节点若同时位于 us-east-1a 可用区且为 c5.large 实例类型,得分为 80 + 20 = 100。
  • 若仅满足可用区条件,得分为 80;仅满足实例类型,得分为 20;均不满足得分为 0。
  • 调度器在所有候选节点中选择得分最高的节点,得分相同时按其他调度策略(如资源均衡)进一步决策。

3.4 节点亲和性调度决策流程

节点亲和性调度决策流程 Pod 创建请求 检查 nodeAffinity 配置 有配置 requiredDuringScheduling 检查 matchExpressions 全部满足? 满足 preferredDuringScheduling 评分 按 weight 加权计算候选节点得分 选择最优节点绑定 Pod 调度失败 Pod 处于 Pending 无配置 默认调度 仅资源调度

3.5 组合使用与最佳实践

在实际生产环境中,requiredDuringScheduling 和 preferredDuringScheduling 通常组合使用,形成"硬约束兜底 + 软偏好优化"的调度策略。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ai-training-job
spec:
  replicas: 3
  template:
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: node-role.kubernetes.io/gpu
                operator: Exists
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 70
            preference:
              matchExpressions:
              - key: topology.kubernetes.io/zone
                operator: In
                values:
                - us-west-2a
          - weight: 30
            preference:
              matchExpressions:
              - key: gpu-memory
                operator: Gt
                values:
                - "80"
      containers:
      - name: trainer
        image: pytorch/pytorch:2.0.0-cuda11.7
组合策略解读:
  • 硬约束:Pod 必须调度到带有 node-role.kubernetes.io/gpu 标签的节点,确保 GPU 资源可用。
  • 软偏好 1(权重 70):优先选择 us-west-2a 可用区,实现可用区亲和,减少跨区网络延迟。
  • 软偏好 2(权重 30):优先选择 GPU 显存大于 80GB 的节点,提升大模型训练性能。
  • 兜底逻辑:若 us-west-2a 区没有满足条件的节点,Pod 仍可调度到其他可用区的 GPU 节点,不会阻塞训练任务。

3.6 常见避坑指南

问题场景 错误示例 正确做法
操作符误用 使用 In 匹配不存在的标签值 使用 Exists 检查标签是否存在,或确保标签值准确
权重设置过高 所有偏好权重设为 100,导致调度器无法区分优先级 按业务重要性分配差异化权重(如 80/20 或 70/30)
硬约束过于严格 同时要求多个稀有标签,导致 Pod 长时间 Pending 使用 nodeSelectorTerms 的 OR 关系提供多个备选条件
忽略运行时变更 期望节点标签变更后自动迁移 Pod 使用 descheduler 或自定义控制器处理运行时重调度
标签命名冲突 使用 kubernetes.io/hostname 等系统标签做亲和性 使用自定义标签(如 workload-type、gpu-class)避免与系统标签混淆
性能注意:当集群规模较大(超过 500 节点)且 preferredDuringScheduling 规则较多时,调度器的评分计算会增加调度延迟。建议将偏好规则控制在 3-5 条以内,权重值使用 10 的倍数便于调试。

3.7 节点亲和性与 nodeSelector 的演进关系

nodeSelector 是 Kubernetes 早期提供的简单节点选择机制,仅支持精确的键值对匹配。节点亲和性在此基础上进行了全面升级:

  • 表达能力:从精确匹配扩展到 In、NotIn、Exists、DoesNotExist、Gt、Lt 六种操作符。
  • 语义维度:从单一硬约束扩展到硬约束 + 软偏好双维度。
  • 组合能力:支持 AND/OR 逻辑组合,实现复杂的调度策略。
  • 扩展性:节点亲和性是调度框架的一部分,可与 Pod 间亲和性、拓扑分布约束协同工作。

在实际 YAML 编写中,nodeSelector 仍可作为一种简写形式存在,但官方推荐使用 nodeAffinity 替代,以获得更灵活的调度控制能力。