3. 节点亲和性与反亲和性:nodeSelector、nodeAffinity、nodeAntiAffinity 原理与配置
在 Kubernetes 调度体系中,节点亲和性(Node Affinity)与节点反亲和性(Node Anti-Affinity)是控制 Pod 与节点之间调度关系的核心机制。它们决定了 Pod 应该被调度到哪些节点上,或者避免调度到哪些节点上。本章将深入剖析 nodeSelector、nodeAffinity 和 nodeAntiAffinity 的原理、配置语法及典型应用场景。
3.1 基础选择器:nodeSelector
nodeSelector 是最简单、最直接的节点选择方式。它通过 Pod 规约中的 nodeSelector 字段,指定一组键值对标签(Label),调度器只会将 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)。调度器会计算所有满足条件的偏好权重之和,得分最高的节点被选中。
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 |
| 适用场景 | 简单标签过滤 | 复杂节点选择、分层偏好 | 节点排除、故障域隔离 |
| 配置复杂度 | 低 | 中 | 中 |
3.5 最佳实践与避坑指南
- 优先使用软性偏好: 在非关键路径上使用
preferredDuringScheduling,避免因节点标签缺失导致 Pod 无法调度。 - 合理设置权重: 软性偏好的权重值应反映业务优先级,避免所有偏好权重相同导致调度器无法区分。
- 结合 Pod 反亲和性: 节点反亲和性控制 Pod 与节点的关系,Pod 反亲和性控制 Pod 与 Pod 的关系,两者互补使用效果更佳。
- 标签命名规范: 使用
topology.kubernetes.io/*等标准前缀,便于跨团队理解和维护。
- 忽略 IgnoredDuringExecution: 节点标签在 Pod 运行后发生变化,调度器不会重新调度已运行的 Pod。如需响应标签变化,需使用
descheduler或自定义控制器。 - 过度使用硬性要求: 过多的
requiredDuringScheduling条件可能导致 Pod 长时间处于Pending状态,降低集群资源利用率。 - 权重值冲突: 多个软性偏好权重值差距过大时,高权重偏好可能完全主导调度决策,使低权重偏好形同虚设。
通过合理组合 nodeSelector、nodeAffinity 和 nodeAntiAffinity,可以实现精细化的节点调度策略,为后续基于网络拓扑的亲和性设计奠定坚实基础。