4. 节点亲和性调度:nodeSelector、nodeAffinity硬策略、nodeAffinity软策略、权重配置

在Kubernetes集群中,Pod调度到哪个节点并非完全随机。节点亲和性(Node Affinity)是调度器将Pod绑定到特定节点的一组规则,它比简单的 nodeSelector 更灵活、表达能力更强。本章从最基础的 nodeSelector 出发,逐步深入到 nodeAffinity 的硬策略(required)、软策略(preferred)以及权重配置,帮助你精准控制Pod的放置位置。

4.1 基础选择器:nodeSelector

nodeSelector 是Kubernetes最早提供的节点选择机制,它通过Pod的 spec.nodeSelector 字段指定一组键值对标签,调度器只将Pod调度到包含所有这些标签的节点上。这是一种“与(AND)”逻辑——所有条件必须同时满足。

适用场景: 简单、静态的节点选择需求,例如将GPU工作负载调度到带有 gpu=true 标签的节点。
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  nodeSelector:
    gpu: "true"          # 节点必须包含标签 gpu=true
  containers:
  - name: cuda-container
    image: nvidia/cuda:11.0-base
特性 nodeSelector nodeAffinity
表达式能力 仅支持精确键值对匹配(=) 支持 In、NotIn、Exists、DoesNotExist、Gt、Lt 等操作符
逻辑组合 多个条件之间为 AND 关系 支持 AND(同一规则内)和 OR(多个 matchExpressions)
软/硬策略 硬性要求(不满足则不调度) 支持硬策略(required)和软策略(preferred)
权重 不支持 软策略支持权重(weight 1-100)

4.2 nodeAffinity 硬策略(requiredDuringSchedulingIgnoredDuringExecution)

硬策略要求Pod必须调度到满足条件的节点上,否则Pod将处于 Pending 状态。其名称中的 IgnoredDuringExecution 表示:即使Pod运行后节点标签发生变化,已经运行的Pod也不会被驱逐。

apiVersion: v1
kind: Pod
metadata:
  name: ssd-pod
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disk-type
            operator: In
            values:
            - ssd
            - nvme
  containers:
  - name: app
    image: nginx:1.21
关键点: nodeSelectorTerms 列表中的多个 matchExpressions 之间是 OR 关系(满足任一即可);而同一个 matchExpressions 内的多个条件之间是 AND 关系(必须全部满足)。

4.3 nodeAffinity 软策略(preferredDuringSchedulingIgnoredDuringExecution)

软策略是“尽力而为”的调度偏好。调度器会优先选择满足条件的节点,但如果找不到符合条件的节点,Pod仍然可以被调度到其他节点上。软策略必须配合 weight 字段使用,权重值范围为 1-100,权重越高,调度器越倾向于选择该节点。

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 80
        preference:
          matchExpressions:
          - key: zone
            operator: In
            values:
            - us-east-1
      - weight: 20
        preference:
          matchExpressions:
          - key: instance-type
            operator: In
            values:
            - c5.large
  containers:
  - name: app
    image: nginx:1.21
注意: 软策略的权重是 相对值,调度器会计算每个候选节点的总得分(所有匹配的软策略权重之和),得分最高的节点被选中。如果多个节点得分相同,调度器会随机选择一个。

4.4 权重配置与调度决策流程

当同时使用多个软策略时,权重决定了调度器的偏好优先级。下面的SVG图展示了调度器如何综合硬策略和软策略做出最终决策。

节点亲和性调度决策流程 Pod 亲和性定义 硬策略检查 requiredDuringScheduling 硬策略满足? Pending 无法调度 继续软策略 软策略权重计算 preferredDuringScheduling 候选节点评分 NodeA: 80分 | NodeB: 50分 | NodeC: 20分 选择最高分节点调度

4.5 多策略组合实战

在实际生产环境中,硬策略和软策略经常组合使用。例如:要求Pod必须运行在SSD节点上(硬策略),同时优先选择低负载的节点(软策略)。

apiVersion: v1
kind: Pod
metadata:
  name: production-app
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disk-type
            operator: In
            values:
            - ssd
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 70
        preference:
          matchExpressions:
          - key: node-load
            operator: NotIn
            values:
            - high
      - weight: 30
        preference:
          matchExpressions:
          - key: zone
            operator: In
            values:
            - zone-a
  containers:
  - name: app
    image: myapp:latest
最佳实践:
  • 硬策略用于强制约束(如合规、安全、硬件要求),数量不宜过多(建议 ≤ 3 个)。
  • 软策略用于性能优化或成本控制,权重值应体现业务优先级差异(如 80 vs 20 比 50 vs 40 更清晰)。
  • 避免在软策略中使用 operator: Exists 或 DoesNotExist 这类宽泛条件,否则可能导致调度结果不可预测。

4.6 操作符对比与选择

操作符 含义 示例 适用场景
In 标签值在给定集合中 zone In [us-east-1, us-west-2] 多区域部署,指定可用区
NotIn 标签值不在给定集合中 node-type NotIn [spot] 排除竞价实例节点
Exists 节点存在该标签(不关心值) gpu Exists 只要节点有GPU标签即可
DoesNotExist 节点不存在该标签 maintenance DoesNotExist 排除维护中的节点
Gt 标签值大于指定数值(字符串比较) memory Gt 32 内存大于32GB的节点
Lt 标签值小于指定数值 cpu-cores Lt 8 CPU核心数小于8的节点
性能提示: 使用 Gt 和 Lt 操作符时,标签值会被解析为数值进行比较。如果标签值不是纯数字(如 32GB),比较结果可能不符合预期。建议在节点标签中使用纯数字表示资源量。

4.7 常见问题与排查

  • Pod一直Pending: 检查硬策略是否过于严格,使用 kubectl describe pod <pod-name> 查看调度事件,确认是否有 0/3 nodes are available 的提示。
  • 软策略未生效: 确认权重值是否在 1-100 范围内,且 preference 字段下的 matchExpressions 语法正确。
  • 标签拼写错误: 使用 kubectl get nodes --show-labels 验证节点标签的实际键值对。
  • 多个nodeSelectorTerms的OR逻辑混淆: 记住:nodeSelectorTerms 列表项之间是 OR,matchExpressions 列表项之间是 AND。