2. Node亲和性:nodeSelector、nodeAffinity(required/preferred)配置与实战
Node亲和性是Kubernetes调度器将Pod绑定到特定节点的一组策略,属于调度约束的核心能力。与污点/容忍的“排斥-容忍”逻辑不同,亲和性采用“吸引-匹配”机制,主动引导Pod选择符合条件的节点。本章从最基础的nodeSelector入手,逐步深入到nodeAffinity的强制与偏好规则,并通过实战案例展示配置方法。
2.1 nodeSelector:最简单的节点选择器
nodeSelector是Kubernetes最早提供的节点选择机制,通过在Pod的spec中定义nodeSelector字段,要求节点必须包含指定的标签且值匹配。它只支持“与”逻辑(所有条件必须同时满足),不支持复杂表达式。
- 语法简单,仅需在Pod spec中设置
nodeSelector: { key: value }。 - 只支持精确匹配(等于),不支持
In、NotIn、Exists等操作符。 - 多个条件之间是AND关系,所有标签必须同时存在于节点上。
- 如果没有任何节点满足条件,Pod将处于Pending状态。
配置示例:
apiVersion: v1
kind: Pod
metadata:
name: nginx-selector
spec:
nodeSelector:
disktype: ssd
region: cn-east-1
containers:
- name: nginx
image: nginx:1.25
上述Pod只会被调度到同时具有disktype=ssd和region=cn-east-1标签的节点上。如果集群中没有这样的节点,Pod将一直Pending。
kubectl label node <node-name> disktype=ssd为节点打标签,再创建使用nodeSelector的Pod。避免因标签缺失导致调度失败。
2.2 nodeAffinity:增强型节点亲和性
nodeAffinity是nodeSelector的升级版,属于调度策略的进阶能力。它支持丰富的匹配操作符(In、NotIn、Exists、DoesNotExist、Gt、Lt),并分为两种类型:requiredDuringSchedulingIgnoredDuringExecution(硬亲和)和preferredDuringSchedulingIgnoredDuringExecution(软亲和)。
| 类型 | 语义 | 调度行为 | 执行阶段 |
|---|---|---|---|
| required | 硬亲和(必须满足) | 节点必须满足所有规则,否则Pod无法调度 | 调度时强制执行,运行期间忽略节点变化 |
| preferred | 软亲和(尽量满足) | 调度器优先选择满足规则的节点,不满足时仍可调度到其他节点 | 调度时尽力满足,运行期间忽略节点变化 |
2.3 requiredDuringScheduling 实战配置
硬亲和适用于强依赖场景,例如GPU计算节点、特定硬件节点、合规区域节点。以下示例要求Pod必须调度到GPU节点且区域为cn-east:
apiVersion: v1
kind: Pod
metadata:
name: gpu-inference
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: gpu-type
operator: In
values:
- nvidia-a100
- nvidia-h100
- key: topology.kubernetes.io/zone
operator: In
values:
- cn-east-1a
- cn-east-1b
containers:
- name: inference
image: inference:latest
resources:
limits:
nvidia.com/gpu: 1
关键解析:
nodeSelectorTerms:多个term之间是OR关系,满足任意一个term即可。matchExpressions:同一个term内的多个表达式是AND关系,必须全部满足。- 操作符
In:节点的标签值必须匹配values列表中的任意一个。 - 如果集群中没有同时满足
gpu-type和zone条件的节点,Pod将无法调度。
2.4 preferredDuringScheduling 实战配置
软亲和适用于优化调度场景,例如优先将Pod调度到低延迟区域或高带宽节点,但不强制。调度器会为每个节点计算权重分数,分数越高越优先选择。
apiVersion: v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 5
template:
metadata:
labels:
app: web
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: network-tier
operator: In
values:
- low-latency
- weight: 20
preference:
matchExpressions:
- key: disk-type
operator: In
values:
- nvme-ssd
containers:
- name: web
image: nginx:1.25
权重计算逻辑:
- 每个preference独立计算,满足条件则累加对应的weight值。
- 调度器将所有满足条件的preference权重相加,得到节点的总得分。
- 得分最高的节点被优先选中;如果多个节点得分相同,调度器按默认策略(如资源均衡)选择。
- 如果没有任何节点满足preference,Pod仍然可以调度到任意节点(权重为0)。
2.5 nodeSelector 与 nodeAffinity 对比
| 特性 | nodeSelector | nodeAffinity (required) | nodeAffinity (preferred) |
|---|---|---|---|
| 匹配操作符 | 仅支持等于(=) | In, NotIn, Exists, DoesNotExist, Gt, Lt | In, NotIn, Exists, DoesNotExist, Gt, Lt |
| 逻辑关系 | AND(所有条件必须满足) | term间OR,表达式间AND | term间OR,表达式间AND |
| 强制程度 | 强制(不满足则Pending) | 强制(不满足则Pending) | 偏好(不满足仍可调度) |
| 权重支持 | 不支持 | 不支持 | 支持(weight 1-100) |
| 适用场景 | 简单标签匹配,快速部署 | 强依赖硬件/区域/合规 | 性能优化、成本控制、负载均衡 |
2.6 亲和性调度流程(SVG图)
下图展示了Kubernetes调度器在处理Node亲和性时的完整决策流程,从Pod创建到最终节点绑定:
2.7 实战:组合使用 nodeSelector 与 nodeAffinity
在实际生产环境中,nodeSelector和nodeAffinity可以同时使用,调度器会先检查nodeSelector(所有标签必须匹配),再检查nodeAffinity的required规则。以下是一个综合示例:
apiVersion: v1
kind: Pod
metadata:
name: hybrid-affinity-pod
spec:
# 第一层:nodeSelector 精确匹配
nodeSelector:
environment: production
affinity:
nodeAffinity:
# 第二层:硬亲和 - 必须属于指定可用区
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- cn-east-1a
- cn-east-1b
# 第三层:软亲和 - 优先选择高内存节点
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 70
preference:
matchExpressions:
- key: memory-size
operator: In
values:
- large
- xlarge
- weight: 30
preference:
matchExpressions:
- key: cpu-arch
operator: In
values:
- amd64
containers:
- name: app
image: app:latest
调度执行顺序:
- 调度器首先过滤出所有
environment=production的节点(nodeSelector)。 - 从这些节点中,进一步筛选出
zone为cn-east-1a或cn-east-1b的节点(required硬亲和)。 - 对剩余节点,根据
memory-size和cpu-arch的权重计算得分,选择最优节点(preferred软亲和)。
nodeSelector是第一道过滤,适合做粗粒度的环境/区域隔离。nodeAffinity required是第二道强制过滤,适合做硬件/合规约束。nodeAffinity preferred是最终优化排序,适合做性能/成本调优。- 三层策略可以叠加使用,但要注意过度约束可能导致Pod无法调度。
2.8 常见问题与避坑指南
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Pod一直Pending | required条件过于严格,没有节点满足所有标签 | 使用kubectl describe pod查看调度事件;检查节点标签是否完整 |
| Pod调度到不符合preferred的节点 | preferred是软约束,不保证一定满足 | 如果必须满足,将preferred改为required |
| nodeSelector和nodeAffinity冲突 | 两个条件同时使用时,必须同时满足 | 检查标签交集是否为空;考虑合并到nodeAffinity中 |
| 节点标签变更后Pod未迁移 | 亲和性只在调度时检查,运行期间不重新评估 | 使用PodDisruptionBudget配合手动驱逐;或升级到支持运行时亲和性的版本 |
| 权重设置不合理导致调度倾斜 | 多个preference权重差异过大或过小 | 权重差异建议在50以上;避免所有preference权重相同 |
kubectl get nodes --show-labels— 查看所有节点标签kubectl describe pod <pod-name>— 查看调度事件和亲和性配置kubectl get events --field-selector involvedObject.name=<pod-name>— 查看调度相关事件kubectl label node <node> <key>=<value> --overwrite— 动态修改节点标签