3. 节点亲和性(nodeAffinity)详解:requiredDuringSchedulingIgnoredDuringExecution 与 preferredDuringSchedulingIgnoredDuringExecution 配置与实战

节点亲和性(nodeAffinity)是 Kubernetes 调度器将 Pod 绑定到特定节点集合的核心策略。与简单的 nodeSelector 相比,nodeAffinity 提供了更丰富的匹配表达式(In、NotIn、Exists、DoesNotExist、Gt、Lt)以及软性(preferred)与硬性(required)两种调度语义。本章从配置语法、匹配逻辑、实战场景三个维度深入拆解两种亲和性模式。

3.1 两种调度语义对比

特性 requiredDuringSchedulingIgnoredDuringExecution preferredDuringSchedulingIgnoredDuringExecution
调度阶段 硬性约束,Pod 必须满足规则才能被调度 软性偏好,调度器尽量满足,但不强制
执行阶段 节点标签变更后,已运行 Pod 不受影响(Ignored) 节点标签变更后,已运行 Pod 不受影响(Ignored)
匹配逻辑 所有 matchExpressions 必须同时满足(AND) 每个表达式按权重累加,总分最高的节点优先
权重 无权重概念 每个表达式可配置 weight(1-100)
典型场景 GPU 节点、合规区域、专用硬件 可用区均衡、成本优化、性能倾斜
关键理解:两种模式名称中的 "IgnoredDuringExecution" 意味着调度器只在 Pod 创建时检查节点标签,Pod 运行后即使节点标签发生变化,也不会驱逐已运行的 Pod。这与 Pod 反亲和性中的 "RequiredDuringExecution" 不同,后者会在运行时强制执行。

3.2 requiredDuringSchedulingIgnoredDuringExecution 配置与实战

硬性亲和性用于 Pod 必须运行在特定节点上的场景。例如:所有 AI 训练任务必须调度到带有 GPU 的节点上。

3.2.1 配置语法

apiVersion: v1
kind: Pod
metadata:
  name: gpu-training-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: training
    image: tensorflow:2.12-gpu

3.2.2 匹配逻辑详解

  • nodeSelectorTerms:多个 term 之间是 OR 关系,满足任意一个 term 即可。
  • matchExpressions:同一个 term 内的多个表达式是 AND 关系,必须全部满足。
  • 支持的运算符:In、NotIn、Exists、DoesNotExist、Gt、Lt。
实战案例:某金融公司要求核心交易 Pod 必须部署在物理隔离的专用节点池,且节点必须位于主可用区。配置两个 matchExpressions 在同一个 term 内,确保节点同时满足 "node-type=dedicated" 和 "zone=primary"。

3.3 preferredDuringSchedulingIgnoredDuringExecution 配置与实战

软性亲和性用于优化调度质量但不阻塞调度的场景。例如:优先将 Pod 调度到低负载节点,但如果所有低负载节点都已满,仍可调度到普通节点。

3.3.1 配置语法

apiVersion: v1
kind: Pod
metadata:
  name: web-frontend
spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 80
        preference:
          matchExpressions:
          - key: node-role.kubernetes.io/worker
            operator: In
            values:
            - "true"
      - weight: 20
        preference:
          matchExpressions:
          - key: topology.kubernetes.io/zone
            operator: In
            values:
            - us-west-2a
  containers:
  - name: nginx
    image: nginx:1.25

3.3.2 权重计算机制

调度器为每个候选节点计算亲和性总分:

节点总分 = Σ(满足的 preference.weight) / 节点上所有 preference 权重总和
  • 权重范围:1-100,数值越大优先级越高。
  • 如果节点满足某个 preference,则累加其 weight;不满足则加 0。
  • 最终得分归一化后,调度器选择得分最高的节点。
注意:preferred 亲和性不会阻止调度。如果集群中没有任何节点满足任何 preference,Pod 仍然会被调度到任意可用节点。这是与 required 模式最本质的区别。

3.4 节点亲和性调度流程

下图展示了调度器在处理 nodeAffinity 时的完整决策路径:

节点亲和性调度决策流程 Pod 创建请求 requiredDuringScheduling 存在? 是 节点匹配所有 matchExpressions? 不匹配 调度失败(Pending) 匹配 preferredDuringScheduling 存在? 否 直接调度 是 计算各节点亲和性权重总分 选择总分最高的节点调度

3.5 实战:多维度节点亲和性组合

在实际生产环境中,通常需要同时使用 required 和 preferred 来达到最佳调度效果。以下是一个电商平台的后端服务配置示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 5
  template:
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: node-type
                operator: In
                values:
                - compute
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 70
            preference:
              matchExpressions:
              - key: topology.kubernetes.io/zone
                operator: In
                values:
                - us-east-1a
                - us-east-1b
          - weight: 30
            preference:
              matchExpressions:
              - key: disk-type
                operator: In
                values:
                - ssd
      containers:
      - name: order
        image: order-service:2.5
调度效果分析:
  • 硬性约束:Pod 只能调度到 node-type=compute 的节点,确保不会跑到 GPU 或内存密集型节点池。
  • 软性偏好:优先选择 us-east-1a 或 us-east-1b 可用区(权重 70),同时尽量选择 SSD 磁盘节点(权重 30)。
  • 容错性:如果两个可用区都无可用节点,Pod 仍可调度到其他可用区的 compute 节点,只是得分较低。

3.6 常见陷阱与最佳实践

陷阱 说明 解决方案
required 表达式过于严格 导致大量 Pod 处于 Pending 状态 使用 NotIn 或 Exists 放宽条件;设置合理的节点标签覆盖范围
preferred 权重设置不合理 权重差距过大导致调度倾斜 权重差异控制在 20-50 之间,避免单一偏好主导
忽略节点标签一致性 部分节点缺少预期标签导致调度失败 使用 Exists 运算符兜底;定期审计节点标签
混合使用 nodeSelector 和 nodeAffinity 两者同时存在时,nodeSelector 会先被评估 统一使用 nodeAffinity 避免混淆
生产建议:在部署关键业务前,先使用 kubectl get nodes --show-labels 确认节点标签的完整性和一致性。对于大规模集群(1000+ 节点),preferred 亲和性的权重计算会增加调度器开销,建议将权重数量控制在 5 个以内。