节点亲和性
学习目标
- 理解 nodeAffinity 的两种类型:required 和 preferred
- 掌握亲和性表达式的语法
- 了解 nodeAffinity 与 nodeSelector 的区别
核心概念
一句话解释
nodeAffinity 是 nodeSelector 的增强版,支持硬性要求和软性偏好两种调度策略。
两种类型
┌─────────────────────────────────────────────────────────┐
│ nodeAffinity 类型 │
├─────────────────────────────────────────────────────────┤
│ │
│ requiredDuringSchedulingIgnoredDuringExecution │
│ ┌─────────────────────────────────────────┐ │
│ │ 硬性要求:必须满足才能调度 │ │
│ │ 类似 nodeSelector,但支持更丰富的表达式 │ │
│ └─────────────────────────────────────────┘ │
│ │
│ preferredDuringSchedulingIgnoredDuringExecution │
│ ┌─────────────────────────────────────────┐ │
│ │ 软性偏好:尽量满足,但不强制 │ │
│ │ 可以指定权重,优先调度到偏好节点 │ │
│ └─────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
YAML 语法
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
affinity:
nodeAffinity:
# 硬性要求
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/e2e-az-name
operator: In
values:
- e2e-az1
- e2e-az2
# 软性偏好
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1 # 权重 1-100
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: app
image: nginx
操作符详解
| 操作符 | 说明 | 示例 |
|---|---|---|
| In | 值在列表中 | values: [ssd, nvme] |
| NotIn | 值不在列表中 | values: [hdd] |
| Exists | 标签存在 | key: gpu(无需 values) |
| DoesNotExist | 标签不存在 | key: gpu(无需 values) |
| Gt | 值大于(字符串比较) | values: ["64"] |
| Lt | 值小于(字符串比较) | values: ["128"] |
调度流程
Pod with nodeAffinity:
required: zone In [east, west]
preferred: disktype=ssd (weight: 80)
gpu=true (weight: 20)
节点列表:
┌─────────┬────────┬─────────┬─────┐
│ Node │ zone │ disktype │ gpu │
├─────────┼────────┼─────────┼─────┤
│ node1 │ east │ ssd │ no │
│ node2 │ west │ hdd │ yes │
│ node3 │ north │ ssd │ yes │
│ node4 │ east │ ssd │ yes │
└─────────┴────────┴─────────┴─────┘
1. 过滤阶段:
- node1: zone=east ✓ 满足 required
- node2: zone=west ✓ 满足 required
- node3: zone=north ✗ 不满足 required
- node4: zone=east ✓ 满足 required
2. 打分阶段(node1, node2, node4):
- node1: disktype=ssd (80分) + gpu=no (0分) = 80分
- node2: disktype=hdd (0分) + gpu=yes (20分) = 20分
- node4: disktype=ssd (80分) + gpu=yes (20分) = 100分
3. 结果:Pod 调度到 node4
与 nodeSelector 对比
| 特性 | nodeSelector | nodeAffinity |
|---|---|---|
| 匹配方式 | 简单标签相等 | 复杂表达式 |
| 硬性约束 | ✓ | ✓ |
| 软性偏好 | ✗ | ✓ |
| 操作符 | 仅 = | In, NotIn, Exists 等 |
| 权重 | ✗ | ✓ |
| 复杂逻辑 | AND only | AND, OR (多 term) |
多 term 关系
# 多个 term 是 OR 关系
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions: # term 1
- key: zone
operator: In
values: [east]
- matchExpressions: # term 2
- key: zone
operator: In
values: [west]
# 满足 term 1 或 term 2 都可以
# 单个 term 内多个 expression 是 AND 关系
nodeSelectorTerms:
- matchExpressions:
- key: zone
operator: In
values: [east]
- key: disktype
operator: In
values: [ssd]
# 必须同时满足 zone=east 和 disktype=ssd
实践练习
练习 1:使用 required nodeAffinity
# pod-node-affinity-required.yaml
apiVersion: v1
kind: Pod
metadata:
name: affinity-required
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
- key: kubernetes.io/arch
operator: In
values:
- amd64
containers:
- name: nginx
image: nginx
kubectl apply -f pod-node-affinity-required.yaml
kubectl get pod affinity-required -o wide
练习 2:使用 preferred nodeAffinity
# pod-node-affinity-preferred.yaml
apiVersion: v1
kind: Pod
metadata:
name: affinity-preferred
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
- weight: 20
preference:
matchExpressions:
- key: gpu
operator: Exists
containers:
- name: nginx
image: nginx
练习 3:组合 required 和 preferred
# pod-node-affinity-both.yaml
apiVersion: v1
kind: Pod
metadata:
name: affinity-both
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: environment
operator: In
values:
- production
- staging
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: environment
operator: In
values:
- production
containers:
- name: nginx
image: nginx
练习 4:使用 NotIn 和 DoesNotExist
# pod-node-affinity-exclude.yaml
apiVersion: v1
kind: Pod
metadata:
name: affinity-exclude
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/master
operator: DoesNotExist
- key: environment
operator: NotIn
values:
- test
containers:
- name: nginx
image: nginx
常见使用场景
# 场景 1:GPU 工作负载
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: accelerator
operator: In
values:
- nvidia-tesla-v100
- nvidia-tesla-a100
# 场景 2:跨可用区高可用
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- zone-a
- zone-b
- zone-c
小结
| 要点 | 说明 |
|---|---|
| required | 硬性要求,必须满足才能调度 |
| preferred | 软性偏好,尽量满足但不强制 |
| 操作符 | In, NotIn, Exists, DoesNotExist, Gt, Lt |
| 权重 | 1-100,用于软性偏好排序 |
| 优势 | 比 nodeSelector 更灵活强大 |
练习编辑器
bash
Loading...