2. Node亲和性:nodeSelector、nodeAffinity的required与preferred规则、多标签匹配策略
Node亲和性(Node Affinity)是Kubernetes调度器将Pod绑定到特定节点的一组规则。与简单的nodeSelector相比,Node亲和性提供了更丰富的表达能力,支持必须满足(required)和倾向满足(preferred)两种语义,以及多标签逻辑组合。本章从基础到进阶,系统讲解这三种调度约束机制。
2.1 nodeSelector:最简标签匹配
nodeSelector是Kubernetes最早提供的节点选择机制,通过在Pod的spec中定义nodeSelector字段,指定一组键值对标签。调度器仅将Pod调度到包含所有指定标签的节点上。
| 特性 | nodeSelector | 适用场景 |
|---|---|---|
| 匹配逻辑 | 仅AND(全部匹配) | 简单固定分组 |
| 表达式能力 | 无(仅键值对) | GPU节点、SSD节点 |
| 软约束 | 不支持 | — |
| 维护成本 | 低 | 小规模集群 |
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
nodeSelector:
accelerator: nvidia-tesla-v100
disktype: ssd
containers:
- name: cuda-container
image: nvidia/cuda:12.0-base
上述Pod只会被调度到同时拥有accelerator=nvidia-tesla-v100和disktype=ssd标签的节点上。如果集群中没有这样的节点,Pod将一直处于Pending状态。
2.2 nodeAffinity:进阶亲和性规则
nodeAffinity是nodeSelector的进化版,属于Pod的affinity字段下的子结构。它支持两种规则类型:requiredDuringSchedulingIgnoredDuringExecution(硬约束)和preferredDuringSchedulingIgnoredDuringExecution(软约束)。
2.2.1 required(硬约束)规则
硬约束规则与nodeSelector效果类似,但支持更丰富的表达式操作符:In、NotIn、Exists、DoesNotExist、Gt、Lt。多个matchExpressions之间默认是AND关系。
apiVersion: v1
kind: Pod
metadata:
name: affinity-required-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- us-east-1a
- us-east-1b
- key: node-type
operator: NotIn
values:
- spot
containers:
- name: app
image: nginx:1.25
上述Pod要求:节点必须位于us-east-1a或us-east-1b可用区,且不能是spot类型。如果两个条件无法同时满足,Pod不会被调度。
2.2.2 preferred(软约束)规则
软约束规则为调度器提供倾向性建议,但不强制。每个preference可以设置weight权重(1-100),调度器会计算所有满足条件的节点得分,得分高的节点优先被选中。
apiVersion: v1
kind: Pod
metadata:
name: affinity-preferred-pod
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
- weight: 20
preference:
matchExpressions:
- key: region
operator: In
values:
- us-east
containers:
- name: app
image: nginx:1.25
调度器会优先选择disktype=ssd的节点(权重80),同时如果节点也在us-east区域(权重20),得分更高。但如果没有SSD节点,Pod仍然可以被调度到普通节点上。
2.3 多标签匹配策略与组合
实际生产环境中,节点标签往往不止两三个。理解多标签的组合逻辑是正确使用Node亲和性的关键。
2.3.1 nodeSelectorTerms 与 matchExpressions 的层级关系
nodeAffinity的nodeSelectorTerms是一个列表,列表内多个term之间是OR关系;每个term内的matchExpressions列表是AND关系。这种设计提供了“或”与“与”的混合表达能力。
2.3.2 多标签组合示例
以下示例展示了一个复杂的多标签匹配策略:Pod优先选择SSD节点且位于us-east区域,但如果没有,也可以接受HDD节点但必须位于us-east区域。
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions: # Term 1: SSD + us-east
- key: disktype
operator: In
values: [ssd]
- key: region
operator: In
values: [us-east]
- matchExpressions: # Term 2: HDD + us-east(备选)
- key: disktype
operator: In
values: [hdd]
- key: region
operator: In
values: [us-east]
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 70
preference:
matchExpressions:
- key: disktype
operator: In
values: [ssd]
matchExpressions在同一term内是AND关系,如果误将“或”逻辑的标签放在同一term内,会导致调度失败。例如“节点标签为A或B”应该拆成两个term,而不是放在一个term内。
2.4 nodeSelector 与 nodeAffinity 的对比与选型
| 对比维度 | nodeSelector | nodeAffinity required | nodeAffinity preferred |
|---|---|---|---|
| 约束强度 | 硬约束 | 硬约束 | 软约束 |
| 操作符支持 | 仅= | In/NotIn/Exists/DoesNotExist/Gt/Lt | In/NotIn/Exists/DoesNotExist/Gt/Lt |
| OR逻辑 | 不支持 | 支持(多term) | 支持(多preference) |
| 权重打分 | 不支持 | 不支持 | 支持(weight 1-100) |
| 运行时标签变化 | 不影响 | 不影响(IgnoredDuringExecution) | 不影响 |
| 推荐场景 | 简单固定分组 | 合规/安全/硬件要求 | 性能优化/负载均衡 |
2.5 最佳实践与避坑指南
- 优先使用nodeAffinity替代nodeSelector:nodeAffinity功能更强大,且未来版本可能弃用nodeSelector。
- required规则不要过于严格:如果硬约束条件过多,可能导致大量Pod处于Pending状态,建议配合
preferred规则兜底。 - 权重设计要合理:preferred规则的weight值差异应足够大(建议至少20分差距),否则调度器可能无法有效区分优先级。
- 标签命名规范:使用
topology.kubernetes.io/*、node.kubernetes.io/*等标准前缀,避免自定义标签冲突。 - 测试验证:使用
kubectl get nodes --show-labels确认节点标签,再用kubectl describe pod <pod-name>查看调度事件。
nodeAffinity与PodAntiAffinity、topologySpreadConstraints配合使用,可以实现更精细的拓扑分布控制,避免单点故障和资源倾斜。