3. 节点亲和性(nodeAffinity):requiredDuringScheduling 与 preferredDuringScheduling

节点亲和性是 Kubernetes 调度器将 Pod 绑定到特定节点集合的核心策略之一。与 nodeSelector 的简单标签匹配不同,nodeAffinity 提供了更丰富的表达式语法和调度语义,支持“硬性必须”和“软性偏好”两种模式,分别对应 requiredDuringScheduling 和 preferredDuringScheduling。

3.1 两种调度语义的本质区别

特性 requiredDuringScheduling(硬亲和) preferredDuringScheduling(软亲和)
调度约束强度 必须满足,否则 Pod 无法调度 尽量满足,不满足时仍可调度到其他节点
表达式语法 matchExpressions + matchFields matchExpressions + weight(权重)
调度失败行为 Pod 处于 Pending 状态,持续重试 忽略该偏好,继续使用其他评分维度
运行时节点标签变更 不影响已运行 Pod(仅调度时检查) 不影响已运行 Pod(仅调度时评分)
典型场景 合规要求、GPU 节点、专用硬件 性能优化、负载均衡、成本控制
关键认知:两种模式名称中的 DuringScheduling 后缀表明,节点亲和性仅在 Pod 调度阶段生效。Kubernetes 不会在运行时重新评估亲和性规则,即使节点标签后续发生变化,已调度的 Pod 也不会被驱逐。

3.2 requiredDuringScheduling:硬性约束的表达式语法

requiredDuringScheduling 使用 matchExpressions 定义一组必须同时满足的标签条件。每个表达式包含 key、operator 和 values 三个字段,支持以下操作符:

  • In:节点的标签值必须属于给定的 values 集合
  • NotIn:节点的标签值不能属于给定的 values 集合
  • Exists:节点必须存在指定的标签 key(不关心值)
  • DoesNotExist:节点不能存在指定的标签 key
  • Gt / Lt:节点的标签值(数值比较)必须大于或小于给定值
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: topology.kubernetes.io/zone
            operator: In
            values:
            - us-east-1a
  containers:
  - name: inference
    image: nvidia/cuda:12.0-base
常见陷阱:nodeSelectorTerms 是一个列表,多个 term 之间是 OR 关系(满足任一 term 即可);而每个 term 内的 matchExpressions 是 AND 关系(必须全部满足)。这种“外层 OR、内层 AND”的设计容易导致配置错误,建议每个 term 只放一组紧密相关的表达式。

3.3 preferredDuringScheduling:软性偏好的权重机制

preferredDuringScheduling 允许为每个偏好规则设置 weight(权重值,1–100),调度器在评分阶段会计算所有满足条件的偏好得分,最终与其他调度维度(如资源可用性、Pod 间亲和性)加权求和。

apiVersion: v1
kind: Pod
metadata:
  name: cache-worker
spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 80
        preference:
          matchExpressions:
          - key: node-type
            operator: In
            values:
            - ssd-optimized
      - weight: 20
        preference:
          matchExpressions:
          - key: topology.kubernetes.io/region
            operator: In
            values:
            - us-west
  containers:
  - name: worker
    image: redis:7-alpine

调度器计算软亲和性得分的公式为:

preferenceScore = (满足的偏好权重之和 / 所有偏好权重之和) × 100

例如上例中,如果一个节点同时满足 ssd-optimized(权重 80)和 us-west(权重 20),则得分为 (80+20)/(80+20) × 100 = 100;如果只满足前者,得分为 80/100 × 100 = 80。

3.4 硬亲和与软亲和的协同工作流

节点亲和性调度决策流程 Pod 调度请求 requiredDuringScheduling 检查 nodeSelectorTerms(OR)→ matchExpressions(AND) ✗ 不满足任何 term Pod 进入 Pending 状态 ✓ 满足至少一个 term 进入软亲和评分阶段 preferredDuringScheduling 评分 weight 加权求和 → 归一化得分 综合评分 → 选择最优节点

3.5 实战调优建议

性能敏感场景:将关键硬件约束(GPU、FPGA、NVMe)放在 requiredDuringScheduling 中,将拓扑偏好(可用区、机型代次)放在 preferredDuringScheduling 中,权重按业务优先级分配。例如,AI 推理 Pod 可以设置 accelerator: In [A100] 为硬约束,topology.kubernetes.io/zone: In [az-a] 为权重 70 的软约束。
避免过度约束:硬亲和条件过多会导致集群资源利用率下降,建议每个 Pod 的 nodeSelectorTerms 不超过 2 个 term,每个 term 内的 matchExpressions 不超过 3 个。软亲和的权重总和建议保持在 100 以内,便于理解和调试。

3.6 与 nodeSelector 的对比

特性 nodeSelector nodeAffinity(required)
表达式能力 仅支持等值匹配(key=value) 支持 In、NotIn、Exists、Gt、Lt
多条件逻辑 多个条件之间为 AND 关系 支持 OR(term 间)+ AND(表达式间)
可读性 简单直观 灵活但配置稍复杂
推荐场景 单一标签的快速筛选 复杂拓扑、多维度约束

在实际生产环境中,建议优先使用 nodeAffinity 替代 nodeSelector,因为前者提供了更丰富的表达能力和更好的可扩展性。对于简单的单标签匹配,nodeSelector 仍然是一个轻量级的选择。