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 时的完整决策路径:
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 个以内。