3. 节点亲和性与反亲和性:nodeSelector、nodeAffinity、nodeAntiAffinity 原理与配置

在 Kubernetes 调度体系中,节点亲和性(Node Affinity)与节点反亲和性(Node Anti-Affinity)是控制 Pod 与节点之间调度关系的核心机制。它们决定了 Pod 应该被调度到哪些节点上,或者避免调度到哪些节点上。本章将深入剖析 nodeSelector、nodeAffinity 和 nodeAntiAffinity 的原理、配置语法及典型应用场景。

3.1 基础选择器:nodeSelector

nodeSelector 是最简单、最直接的节点选择方式。它通过 Pod 规约中的 nodeSelector 字段,指定一组键值对标签(Label),调度器只会将 Pod 调度到包含所有这些标签的节点上。

核心原理: 标签匹配。节点必须拥有 Pod 中 nodeSelector 定义的所有标签,且标签值必须完全一致。

配置示例:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-selector
spec:
  containers:
  - name: nginx
    image: nginx:1.25
  nodeSelector:
    disktype: ssd
    region: us-east-1

上述配置要求目标节点必须同时拥有 disktype=ssd 和 region=us-east-1 两个标签。如果集群中没有节点同时满足这两个条件,Pod 将处于 Pending 状态。

局限性: nodeSelector 仅支持“与(AND)”逻辑,无法表达“或(OR)”、“非(NOT)”或更复杂的条件(如软性偏好)。对于复杂调度需求,必须使用 nodeAffinity。

3.2 高级亲和性:nodeAffinity

nodeAffinity 是 nodeSelector 的进化版,属于 Pod 的 affinity 字段下的子属性。它提供了更丰富的匹配表达式,并支持两种调度策略:硬性要求(requiredDuringSchedulingIgnoredDuringExecution)和软性偏好(preferredDuringSchedulingIgnoredDuringExecution)。

策略类型 语义 调度行为 执行阶段
requiredDuringSchedulingIgnoredDuringExecution 硬性要求 必须满足规则,否则 Pod 无法调度 调度时检查,运行后忽略节点标签变化
preferredDuringSchedulingIgnoredDuringExecution 软性偏好 尽量满足规则,不满足时调度到其他节点 调度时尝试,运行后忽略节点标签变化

匹配表达式类型:

  • In:标签值在给定集合中(或逻辑)。
  • NotIn:标签值不在给定集合中。
  • Exists:节点存在指定标签键(不关心值)。
  • DoesNotExist:节点不存在指定标签键。
  • Gt / Lt:标签值大于/小于给定数值(标签值需为数字字符串)。

配置示例:硬性要求 + 软性偏好

apiVersion: v1
kind: Pod
metadata:
  name: nginx-affinity
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: disktype
            operator: In
            values:
            - ssd
      - weight: 20
        preference:
          matchExpressions:
          - key: gpu
            operator: Exists
  containers:
  - name: nginx
    image: nginx:1.25

上述配置中,Pod 必须调度到 us-east-1a 或 us-east-1b 可用区;在此基础上,优先选择 disktype=ssd 的节点(权重 80),其次选择有 gpu 标签的节点(权重 20)。

权重机制: 软性偏好支持多个 preference,每个可设置 weight(1-100)。调度器会计算所有满足条件的偏好权重之和,得分最高的节点被选中。
nodeAffinity 调度决策流程 Pod 定义 nodeAffinity requiredDuringScheduling 检查 nodeSelectorTerms 匹配成功? (所有条件) Pending preferredDuring 计算权重得分 调度到最优节点

3.3 节点反亲和性:nodeAntiAffinity

节点反亲和性(Node Anti-Affinity)用于表达 Pod 不希望与某些节点特征共存的约束。它同样属于 affinity 字段,但通过 nodeAntiAffinity 子字段定义。其语法结构与 nodeAffinity 完全一致,但语义相反:匹配到的节点将被排除在候选列表之外。

典型应用场景:

  • 故障域隔离: 避免将同一应用的多个副本调度到同一台物理机或同一个可用区。
  • 资源独占: 确保某些敏感 Pod 不会与特定类型的 Pod 共享节点。
  • 硬件隔离: 将 GPU 密集型任务与 CPU 密集型任务分离到不同节点。

配置示例:避免调度到特定可用区

apiVersion: v1
kind: Pod
metadata:
  name: nginx-anti-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: topology.kubernetes.io/zone
            operator: In
            values:
            - us-east-1a
            - us-east-1b
    nodeAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        preference:
          matchExpressions:
          - key: dedicated
            operator: In
            values:
            - gpu-workload
  containers:
  - name: nginx
    image: nginx:1.25

此配置要求 Pod 必须调度到 us-east-1a 或 us-east-1b,同时尽量避开带有 dedicated=gpu-workload 标签的节点。

3.4 三种机制的对比与选择

特性 nodeSelector nodeAffinity nodeAntiAffinity
表达能力 简单键值对匹配 丰富运算符(In/NotIn/Exists/Gt/Lt) 同 nodeAffinity,语义取反
策略类型 仅硬性要求 硬性要求 + 软性偏好 硬性要求 + 软性偏好
逻辑支持 仅 AND AND + OR(通过多个 nodeSelectorTerms) AND + OR
适用场景 简单标签过滤 复杂节点选择、分层偏好 节点排除、故障域隔离
配置复杂度 低 中 中
节点选择机制关系图 Pod 调度请求 nodeSelector 标签精确匹配 nodeAffinity 选择匹配节点 nodeAntiAffinity 排除匹配节点 调度器合并所有约束条件 AND 逻辑:同时满足所有硬性要求 + 最大化软性偏好得分 选定目标节点

3.5 最佳实践与避坑指南

最佳实践:
  • 优先使用软性偏好: 在非关键路径上使用 preferredDuringScheduling,避免因节点标签缺失导致 Pod 无法调度。
  • 合理设置权重: 软性偏好的权重值应反映业务优先级,避免所有偏好权重相同导致调度器无法区分。
  • 结合 Pod 反亲和性: 节点反亲和性控制 Pod 与节点的关系,Pod 反亲和性控制 Pod 与 Pod 的关系,两者互补使用效果更佳。
  • 标签命名规范: 使用 topology.kubernetes.io/* 等标准前缀,便于跨团队理解和维护。
常见陷阱:
  • 忽略 IgnoredDuringExecution: 节点标签在 Pod 运行后发生变化,调度器不会重新调度已运行的 Pod。如需响应标签变化,需使用 descheduler 或自定义控制器。
  • 过度使用硬性要求: 过多的 requiredDuringScheduling 条件可能导致 Pod 长时间处于 Pending 状态,降低集群资源利用率。
  • 权重值冲突: 多个软性偏好权重值差距过大时,高权重偏好可能完全主导调度决策,使低权重偏好形同虚设。

通过合理组合 nodeSelector、nodeAffinity 和 nodeAntiAffinity,可以实现精细化的节点调度策略,为后续基于网络拓扑的亲和性设计奠定坚实基础。