NodeSelector 与 NodeAffinity:节点选择器与节点亲和性配置
在 Kubernetes 集群中,Pod 调度到哪个节点并非完全随机。当集群包含异构节点(如不同 CPU 架构、GPU 机型、磁盘类型或网络区域)时,必须通过节点选择机制将工作负载精确分配到合适的节点。Kubernetes 提供了两种核心机制:NodeSelector(简单标签匹配)和 NodeAffinity(丰富表达式匹配),后者又分为硬亲和(required)与软亲和(preferred)。
1. NodeSelector:最简单的节点选择
NodeSelector 是 Pod 规范中的一个字段,通过 spec.nodeSelector 定义。它要求节点必须包含所有指定的标签键值对,才能调度该 Pod。所有条件之间是逻辑 AND 关系。
disktype=ssd、gpu=true、region=us-east-1。适合简单、静态的调度需求。
apiVersion: v1
kind: Pod
metadata:
name: ssd-pod
spec:
nodeSelector:
disktype: ssd
containers:
- name: app
image: nginx
如果集群中没有节点包含 disktype=ssd 标签,该 Pod 将一直处于 Pending 状态。NodeSelector 不支持取反、集合运算或权重,表达能力有限。
2. NodeAffinity:更强大的节点亲和性
NodeAffinity 是 nodeSelector 的进化版,属于调度器的高级特性。它在 Pod 的 spec.affinity.nodeAffinity 字段中定义,支持丰富的匹配表达式(In、NotIn、Exists、DoesNotExist、Gt、Lt),并且区分两种模式:requiredDuringSchedulingIgnoredDuringExecution(硬亲和)和 preferredDuringSchedulingIgnoredDuringExecution(软亲和)。
| 特性 | NodeSelector | NodeAffinity(硬亲和) | NodeAffinity(软亲和) |
|---|---|---|---|
| 匹配方式 | 精确键值对(AND) | In、NotIn、Exists、DoesNotExist、Gt、Lt | 同左,且支持权重 |
| 调度约束 | 必须满足所有条件 | 必须满足所有条件 | 尽量满足,不满足也可调度 |
| 运行时变更 | 不生效 | 不生效(IgnoredDuringExecution) | 不生效(IgnoredDuringExecution) |
| 权重/优先级 | 不支持 | 不支持 | 支持 weight(1-100) |
| 适用场景 | 简单标签绑定 | 强制分区、合规、硬件要求 | 性能优化、负载均衡、成本控制 |
3. 硬亲和(required):强制调度约束
硬亲和要求节点必须满足所有 matchExpressions 条件,否则 Pod 无法被调度。其行为与 NodeSelector 类似,但表达能力更强。
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: gpu-type
operator: In
values:
- nvidia-tesla
- nvidia-a100
- key: region
operator: In
values:
- us-west-2
containers:
- name: cuda-app
image: nvidia/cuda:12.0-base
上述配置要求节点必须同时满足 gpu-type 为 nvidia-tesla 或 nvidia-a100,且 region 为 us-west-2。多个 matchExpressions 之间是 AND 关系;多个 nodeSelectorTerms 之间是 OR 关系。
4. 软亲和(preferred):优先级调度
软亲和允许调度器将 Pod 调度到不满足条件的节点上,但会优先选择满足条件的节点。每个软亲和规则可以设置 weight(1-100),调度器会计算所有满足条件的节点的总分,选择得分最高的节点。
apiVersion: v1
kind: Pod
metadata:
name: performance-pod
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: disktype
operator: In
values:
- nvme
- weight: 20
preference:
matchExpressions:
- key: zone
operator: In
values:
- zone-a
containers:
- name: app
image: nginx
调度器会优先选择 disktype=nvme 的节点(权重 80),其次选择 zone=zone-a 的节点(权重 20)。如果两个条件都满足,得分累加为 100。如果都不满足,Pod 仍可调度到其他节点。
5. 硬亲和与软亲和对比
| 对比维度 | 硬亲和(required) | 软亲和(preferred) |
|---|---|---|
| 调度失败行为 | Pod 保持 Pending | Pod 调度到其他节点 |
| 权重支持 | 不支持 | 支持(1-100) |
| 典型用途 | 合规、安全、硬件强制要求 | 性能优化、成本控制、负载均衡 |
| 多条件组合 | AND/OR 严格匹配 | 加权评分,灵活选择 |
| 运维风险 | 节点故障可能导致 Pod 无法调度 | 低风险,调度器自动降级 |
6. 节点选择与亲和性工作流
下图展示了从 Pod 创建到节点选择的完整调度流程,以及 NodeSelector 和 NodeAffinity 在其中的作用位置。
7. 组合使用的最佳实践
在实际生产环境中,NodeSelector 和 NodeAffinity 经常组合使用,以实现精细化的调度策略。
- 基础隔离 + 性能优化:使用 NodeSelector 将敏感工作负载限制在特定节点池(如
security-tier=high),同时使用软亲和优先选择 NVMe 磁盘节点。 - 多区域部署:硬亲和要求 Pod 必须调度到
region=us-east的节点,软亲和进一步优先选择zone=a或zone=b。 - GPU 工作负载:硬亲和要求
gpu=true,软亲和优先选择gpu-model=a100的节点。 - 避免单点故障:软亲和可以配合 PodAntiAffinity 使用,将同一应用的多个副本分散到不同节点。
8. 常见问题与避坑
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Pod 一直 Pending | 硬亲和条件没有节点满足 | 检查节点标签;使用 kubectl describe node 查看标签;考虑添加软亲和作为降级 |
| 软亲和未生效 | 权重设置过低,或所有节点都不满足 | 提高权重;检查标签是否一致;使用 kubectl get nodes --show-labels 验证 |
| 标签拼写错误 | 键或值大小写、空格不一致 | 使用 kubectl label 统一管理标签;通过 CI/CD 自动化打标 |
| 忽略运行时标签变更 | 亲和性策略后缀为 IgnoredDuringExecution | 如需运行时响应,需自定义调度器或使用 descheduler |
NodeSelector 和 NodeAffinity 是 Kubernetes 调度体系的基础组件。掌握硬亲和与软亲和的区别,能够帮助你在不同场景下做出正确的调度决策,从而提升集群资源利用率和应用性能。