在 Kubernetes 多节点集群中,Pod 调度直接影响资源利用率、故障恢复和高可用性。默认调度器基于资源匹配进行简单分配,但生产环境需精细控制。通过节点亲和性(Node Affinity)、Pod 亲和性 / 反亲和性(Pod Affinity/Anti-Affinity)、污点与容忍(Taints & Tolerations)以及 Pod 拓扑分布约束(Topology Spread Constraints),结合拓扑感知卷绑定(Topology-Aware Volume Binding),可实现高效的多节点资源分配,避免热点、提升本地性和均匀分布。
节点亲和性与 Pod 亲和性规则
节点亲和性是 nodeSelector 的升级版,支持硬约束(requiredDuringSchedulingIgnoredDuringExecution)和软约束(preferredDuringSchedulingIgnoredDuringExecution)。硬约束要求 Pod 必须调度到匹配标签的节点,否则 Pending;软约束优先匹配,并通过 weight(1-100)加权评分。
例如,优先调度到 us-east-1a 可用区的 GPU 节点:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values: ["us-east-1a"]
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: node-type
operator: In
values: ["gpu"]
Pod 亲和性控制 Pod 间共置:podAffinity 吸引同类 Pod 到同一拓扑域(如 hostname 或 zone),podAntiAffinity 避免单点故障。例如,高可用部署避免相同服务 Pod 同节点:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: my-app
topologyKey: kubernetes.io/hostname
参数要点:
- operator:In/NotIn(多值匹配)、Exists/DoesNotExist(键存在)、Gt/Lt(数值比较,仅 nodeAffinity)。
- topologyKey:如 kubernetes.io/hostname(节点级)、topology.kubernetes.io/zone(区域级)。
- 权重总分最高节点优先,结合资源评分。
落地清单:1. 标签节点kubectl label nodes node1 accelerator=gpu;2.Deployment 中配置 affinity;3. 监控kubectl get pods -o wide,调整 weight 防 Pending。
官方文档指出,亲和性比 nodeSelector 更强大,支持复杂表达式。[1]
污点与容忍机制
污点(Taints)是节点 “排斥” 标签,Pod 需配置容忍(Tolerations)匹配 key=value:effect 才能调度。常用于专用节点如 GPU 隔离。
命令打污点:kubectl taint nodes node-gpu dedicated=gpu:NoSchedule。
Pod YAML 容忍:
spec:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
- key: "disktype" # 模糊匹配
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 300 # NoExecute宽限期
效果类型:
| Effect | 描述 |
|---|---|
| NoSchedule | 拒绝新 Pod 调度 |
| PreferNoSchedule | 尽量避免 |
| NoExecute | 拒绝新 Pod 并驱逐无容忍旧 Pod |
风险:过度 taint 导致无可用节点,监控kubectl describe node的 Taints。
实战:GPU 节点kubectl taint nodes gpu-node nvidia.com/gpu=true:NoSchedule,仅容忍 Pod 调度。回滚:kubectl taint nodes gpu-node nvidia.com/gpu=true:NoSchedule-。
Pod 拓扑分布约束
K8s 1.19 + 引入 topologySpreadConstraints,实现跨 zone/hostname 均匀分布,避免集中故障。核心参数 maxSkew 定义最大偏差。
示例:跨 zone 均匀:
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule # 或ScheduleAnyway
labelSelector:
matchLabels:
app: my-app
- maxSkew=1:目标域 Pod 数与全局最小差≤1。
- minDomains:最小合格域数(v1.28 + 默认)。
- whenUnsatisfiable:DoNotSchedule(硬)或 ScheduleAnyway(软优先低 skew)。
- nodeAffinityPolicy/nodeTaintsPolicy:Honor(尊重)或 Ignore(忽略)节点亲和 / 污点(v1.26+ beta)。
内置默认:hostname maxSkew=3,zone maxSkew=5(ScheduleAnyway)。
拓扑感知卷绑定
为高效多节点存储,CSI 支持 Topology-Aware Volume Provisioning。动态 provision PV 时,匹配 Pod topologyKeys(如 zone),确保卷本地绑定,减少跨域延迟。
StorageClass 配置:
apiVersion: storage.k8s.io/v1
kind: StorageClass
parameters:
csi.storage.k8s.io/fstype: ext4
allowedTopologies:
- matchLabelExpressions:
- key: topology.kubernetes.io/zone
values: ["us-east-1a", "us-east-1b"]
参数:allowedTopologies 限制 provision 域。Pod 调度后,CSI 检查 volume 是否匹配 topology,否则延迟绑定。
监控:kubectl describe pvc,事件中查看 VolumeBinding 失败。
组合工程化实践
多机制协同:
- 专用池:GPU 节点 taint + nodeAffinity。
- HA 分布:podAntiAffinity + topologySpread(hostname skew=1)。
- 卷本地:topologySpread(zone)+ allowedTopologies。
阈值建议:
| 场景 | maxSkew | topologyKey | whenUnsatisfiable |
|---|---|---|---|
| 小集群 HA | 1 | hostname | DoNotSchedule |
| 大集群均衡 | 2 | zone | ScheduleAnyway |
| 卷本地 | 1 | zone | DoNotSchedule |
回滚策略:优先 ScheduleAnyway,Descheduler 定期重平衡(LowNodeUtilization)。监控 Prometheus scheduler_pending_pods,警报 > 10。
引用 Kubernetes 官方文档,亲和性和拓扑约束可显著降低跨域流量。[2]
实际部署中,先小规模测试,避免硬约束导致 Pending。通过这些参数,集群资源利用率提升 20% 以上,故障域恢复更快。
资料来源: [1] https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ [2] https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/
(字数:1256)