3. 节点亲和性(Node Affinity)基础:requiredDuringSchedulingIgnoredDuringExecution 与 preferredDuringSchedulingIgnoredDuringExecution
节点亲和性(Node Affinity)是 Kubernetes 调度器将 Pod 绑定到特定节点的一种声明式规则。与简单的 nodeSelector 相比,Node Affinity 提供了更丰富的匹配表达式和更灵活的调度策略,是精细化节点池配置的核心工具。
3.1 为什么需要 Node Affinity?
在滚动升级节点池时,我们通常希望:
- 强制绑定:某些关键 Pod 必须运行在特定硬件(如 GPU、SSD)或特定节点池上。
- 倾向调度:在满足基本可用性的前提下,优先将 Pod 调度到性能更优或成本更低的节点池。
- 避免冲突:防止 Pod 被调度到不兼容的节点(如操作系统版本、内核参数差异)。
Node Affinity 通过两种语义实现上述需求:requiredDuringSchedulingIgnoredDuringExecution(硬约束)和 preferredDuringSchedulingIgnoredDuringExecution(软约束)。
3.2 两种调度策略对比
| 特性 | requiredDuringSchedulingIgnoredDuringExecution | preferredDuringSchedulingIgnoredDuringExecution |
|---|---|---|
| 语义 | 硬性要求,调度时必须满足 | 软性偏好,调度时尽量满足 |
| 调度失败行为 | Pod 无法调度,Pending 状态 | 忽略偏好,调度到其他可用节点 |
| 执行阶段 | 仅在调度时检查 | 仅在调度时检查 |
| 运行时变更 | 忽略(不驱逐已有 Pod) | 忽略(不驱逐已有 Pod) |
| 权重支持 | 不支持 | 支持(weight 1-100) |
| 典型场景 | GPU 节点、合规节点、专用节点池 | 高性能节点优先、成本优化、区域分布 |
命名解读: 两个策略的后缀均为
IgnoredDuringExecution,意味着一旦 Pod 成功运行,即使节点标签发生变化,Kubernetes 也不会主动驱逐该 Pod。这是与 requiredDuringSchedulingRequiredDuringExecution(未来特性)的关键区别。
3.3 硬约束:requiredDuringSchedulingIgnoredDuringExecution
硬约束是调度器必须遵守的规则。如果没有任何节点满足条件,Pod 将一直处于 Pending 状态。其配置结构如下:
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: accelerator
operator: In
values:
- nvidia-tesla-v100
- nvidia-a100
containers:
- name: gpu-container
image: nvidia/cuda:12.0-base
关键字段说明:
nodeSelectorTerms:多个条件之间是 OR 关系,满足任一即可。matchExpressions:同一条件内的多个表达式是 AND 关系,必须全部满足。operator:支持In、NotIn、Exists、DoesNotExist、Gt、Lt。
3.4 软约束:preferredDuringSchedulingIgnoredDuringExecution
软约束为调度器提供偏好建议。调度器会计算每个候选节点的得分,得分越高越优先被选中。其配置结构如下:
apiVersion: v1
kind: Pod
metadata:
name: performance-pod
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: node-type
operator: In
values:
- high-performance
- weight: 20
preference:
matchExpressions:
- key: zone
operator: In
values:
- us-east-1a
containers:
- name: app
image: nginx:1.25
权重计算逻辑:
- 每个偏好规则独立计算,满足则累加对应 weight。
- 所有满足规则的 weight 之和即为该节点的总分。
- 调度器在所有可调度节点中选择总分最高的节点。
- 如果所有节点都不满足任何偏好,Pod 仍会被调度到任意可用节点。
3.5 调度决策流程
3.6 操作符详解
| 操作符 | 行为 | 示例 |
|---|---|---|
In |
标签值在指定列表中 | values: [ssd, nvme] |
NotIn |
标签值不在指定列表中 | values: [hdd] |
Exists |
标签键存在(不关心值) | key: gpu |
DoesNotExist |
标签键不存在 | key: spot-instance |
Gt |
标签值大于指定数值(字符串比较) | values: [4](vCPU > 4) |
Lt |
标签值小于指定数值(字符串比较) | values: [8](内存 < 8GB) |
3.7 实战建议与避坑
最佳实践:
- 对关键业务 Pod 使用
requiredDuringScheduling确保资源隔离。 - 对弹性工作负载使用
preferredDuringScheduling配合权重,实现成本与性能的平衡。 - 避免在
requiredDuringScheduling中使用过于严格的标签匹配,防止节点标签变更导致 Pod 大规模 Pending。 - 结合
topologySpreadConstraints使用,实现跨可用区的高可用部署。
常见陷阱:
- 误将
nodeSelectorTerms中的多个条件理解为 AND 关系(实际是 OR)。 - 忘记给节点打标签,导致硬约束无法满足,Pod 一直 Pending。
- 软约束权重设置过高(如 100),导致调度器过度倾斜,忽略其他调度策略。
- 在滚动升级时,新旧节点池标签不一致,导致 Pod 调度到错误的节点池。
3.8 与 nodeSelector 的对比
| 特性 | nodeSelector | Node Affinity |
|---|---|---|
| 表达能力 | 仅支持精确匹配 | 支持 In/NotIn/Exists/Gt/Lt 等 |
| 软约束 | 不支持 | 支持权重偏好 |
| 多条件组合 | AND 关系 | 支持 OR + AND 组合 |
| 可读性 | 简单直观 | 配置稍复杂,但更灵活 |
| 推荐场景 | 简单标签匹配 | 复杂调度策略、节点池管理 |