调度策略与算法:默认调度策略、节点亲和性、Pod亲和性与反亲和性
Kubernetes 调度器(kube-scheduler)的核心职责是将待调度的 Pod 绑定到最合适的节点上。调度过程分为两个阶段:过滤(Predicates) 和 打分(Priorities)。本章深入剖析默认调度策略、节点亲和性(nodeAffinity)以及 Pod 亲和性/反亲和性(podAffinity / podAntiAffinity),帮助你在生产环境中精准控制 Pod 的放置位置。
1. 默认调度策略:过滤与打分机制
调度器首先通过一组过滤规则(Predicates)排除不满足条件的节点,然后对剩余节点进行打分(Priorities),最终选择得分最高的节点运行 Pod。
关键过滤策略(Predicates):
- PodFitsResources: 检查节点剩余 CPU、内存是否满足 Pod 的 requests。
- PodFitsHostPorts: 检查 Pod 请求的端口是否已被占用。
- MatchNodeSelector: 检查节点标签是否匹配 Pod 的 nodeSelector。
- NoDiskConflict: 检查卷挂载是否冲突。
- CheckNodeCondition: 排除网络不可用、磁盘压力等异常节点。
关键打分策略(Priorities):
- LeastRequestedPriority: 优先选择资源利用率低的节点,实现负载均衡。
- BalancedResourceAllocation: 优先选择 CPU 和内存使用率最均衡的节点。
- NodeAffinityPriority: 根据节点亲和性规则的权重进行加分。
- ImageLocalityPriority: 优先选择已存在所需容器镜像的节点,减少拉取时间。
2. 节点亲和性(nodeAffinity)
节点亲和性是对 nodeSelector 的增强,支持更丰富的匹配表达式和优先级控制。它分为两种类型:
| 类型 | 语义 | 调度阶段 | 典型场景 |
|---|---|---|---|
| requiredDuringSchedulingIgnoredDuringExecution | 硬性要求:节点必须满足规则,否则 Pod 无法调度 | 过滤阶段 | GPU 节点、合规区域限制 |
| preferredDuringSchedulingIgnoredDuringExecution | 软性偏好:尽量满足,不满足时仍可调度到其他节点 | 打分阶段 | 靠近缓存服务、成本优化 |
最佳实践: 使用
preferredDuringScheduling 时,务必设置 weight 字段(1-100),权重越高,调度器越倾向于满足该规则。
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: gpu-type
operator: In
values:
- nvidia-tesla-v100
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: zone
operator: In
values:
- us-east-1a
containers:
- name: gpu-container
image: nvidia/cuda:11.0-base
3. Pod 亲和性与反亲和性
Pod 亲和性/反亲和性允许你根据 已有 Pod 的标签 来决定新 Pod 的调度位置,而非仅依赖节点标签。这是实现微服务就近部署、故障域隔离的核心手段。
3.1 核心概念
| 概念 | 说明 | 拓扑键(topologyKey) |
|---|---|---|
| podAffinity | 新 Pod 倾向于与满足标签条件的 Pod 运行在同一拓扑域 | kubernetes.io/hostname(同一节点) failure-domain.beta.kubernetes.io/zone(同一可用区) |
| podAntiAffinity | 新 Pod 倾向于不与满足标签条件的 Pod 运行在同一拓扑域 | 同上,用于分散部署 |
| required / preferred | 与节点亲和性类似,分为硬性要求和软性偏好 | — |
3.2 典型配置示例
场景一:将 Web Pod 与 Redis Pod 调度到同一节点(降低延迟)
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- redis
topologyKey: kubernetes.io/hostname
containers:
- name: web
image: nginx:latest
场景二:将同一服务的多个副本分散到不同节点(高可用)
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 5
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- frontend
topologyKey: kubernetes.io/hostname
containers:
- name: nginx
image: nginx:latest
性能警告: 在大型集群(数千节点)中使用
requiredDuringScheduling 的 Pod 反亲和性时,调度器需要遍历所有节点上的 Pod 标签,可能导致调度延迟显著增加。建议优先使用 preferredDuringScheduling 或缩小 topologyKey 范围。
4. 调度策略对比总结
| 策略 | 作用对象 | 匹配方式 | 典型用途 | 性能影响 |
|---|---|---|---|---|
| nodeSelector | 节点标签 | 精确键值匹配 | 简单硬件分类 | 低 |
| nodeAffinity | 节点标签 | 表达式匹配 + 权重 | 复杂节点选择、区域偏好 | 中 |
| podAffinity | Pod 标签 | 表达式匹配 + 拓扑键 | 服务就近部署、缓存亲和 | 中高 |
| podAntiAffinity | Pod 标签 | 表达式匹配 + 拓扑键 | 故障域隔离、分散部署 | 高(required 模式) |
5. 生产环境调度策略选择指南
- 简单硬件隔离: 使用
nodeSelector或nodeAffinity required绑定 GPU、SSD 等特殊节点。 - 区域容灾与成本优化: 使用
nodeAffinity preferred配合多可用区标签,优先调度到低成本区域。 - 微服务通信优化: 使用
podAffinity required将频繁通信的服务(如 Web + Cache)调度到同一节点或同一可用区。 - 高可用与故障隔离: 使用
podAntiAffinity preferred将同一服务的多个副本分散到不同节点或不同可用区。 - 避免调度热点: 对于大规模集群,反亲和性优先使用
preferred模式,并合理设置topologyKey为zone而非hostname,减少调度器压力。
调试命令: 使用
kubectl describe pod <pod-name> 查看调度事件;使用 kubectl get nodes --show-labels 检查节点标签;使用 kubectl get pods -o wide 确认 Pod 分布情况。