预约咨询 提交工单

Kubernetes 调度与容量治理:让 Pod 放得下、跑得稳、扩得动

深入理解 K8s 调度链路、资源请求、优先级、亲和性、污点容忍和容量治理,避免集群在高峰期出现 Pending、抢占和雪崩。

K8s 17min 16 浏览 2026-06-05
KubernetesSchedulerCapacityHPAVPA

Kubernetes 调度与容量治理:让 Pod 放得下、跑得稳、扩得动

Kubernetes 调度看似简单:创建 Pod,调度器选择节点,kubelet 拉起容器。生产环境里,它往往是稳定性问题的放大器。资源请求设置不准、节点池规划混乱、亲和性规则过度复杂、优先级设计缺失,都会导致 Pod 长时间 Pending、关键服务被挤压、扩容动作赶不上流量变化。

容量治理的目标不是让节点利用率永远最高,而是在成本、弹性和稳定性之间取得平衡。一个健康的集群应当做到:关键服务有资源保障,批处理任务不会干扰在线业务,高峰期能扩得动,故障时有足够冗余。

调度链路

K8s 调度器主要经历过滤和打分两个阶段。过滤阶段排除不满足条件的节点,例如资源不足、节点选择器不匹配、污点不可容忍、PVC 绑定限制、端口冲突。打分阶段在可用节点中选择更合适的节点,例如资源均衡、亲和性偏好、拓扑分布。

当 Pod Pending 时,先看事件:

kubectl describe pod <pod> -n <namespace>

常见原因包括:

  • Insufficient cpuInsufficient memory
  • node(s) had untolerated taint
  • node(s) didn't match Pod's node affinity
  • pod has unbound immediate PersistentVolumeClaims
  • Too many pods

不要只看节点实际 CPU 使用率。调度器依据的是资源请求 requests,不是当前使用率。节点看起来很空,但如果已分配请求量接近上限,新 Pod 仍然无法调度。

Requests 与 Limits

requests 决定调度和资源保障,limits 决定资源上限。很多集群的问题来自两个极端:完全不设置 requests,或给所有服务设置过高 requests。

推荐策略:

  • 在线服务必须设置 CPU 和内存 requests。
  • 内存 limit 应谨慎设置,避免 OOMKilled 变成常态。
  • CPU limit 不一定必须设置,尤其是延迟敏感服务,过低 CPU limit 会引入 throttling。
  • 批处理任务可以设置较低优先级,结合 namespace ResourceQuota 控制总体消耗。

可以通过如下指标观察 CPU throttling:

rate(container_cpu_cfs_throttled_periods_total[5m])
/
rate(container_cpu_cfs_periods_total[5m])

如果核心服务 throttling 长期较高,说明 CPU limit 可能过紧,或者应用线程模型与 CPU 配额不匹配。

节点池规划

生产集群建议按工作负载类型规划节点池,而不是把所有 Pod 混跑在同一批节点上。常见节点池包括:

  • system:运行 CoreDNS、Ingress、监控、日志等平台组件。
  • online:运行在线业务服务。
  • batch:运行离线任务、CI Runner、定时 Job。
  • stateful:运行对磁盘、网络或稳定性要求更高的有状态服务。
  • gpu 或 high-memory:运行特殊资源服务。

节点池之间通过 taints、tolerations、nodeSelector 或 nodeAffinity 建立边界。平台组件节点池可以设置污点,只有明确容忍的系统 Pod 才能调度上去。

tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "system"
    effect: "NoSchedule"
nodeSelector:
  nodepool: system

亲和性与拓扑分布

亲和性规则可以表达“必须跑在某类节点”或“尽量靠近/远离某些 Pod”。但规则越多,调度越难,故障时越容易无节点可选。

高可用服务建议使用 topologySpreadConstraints,让副本跨节点、可用区或机架分布:

topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: ScheduleAnyway
    labelSelector:
      matchLabels:
        app: checkout

如果业务要求强隔离,可以把 whenUnsatisfiable 设置为 DoNotSchedule,但这会牺牲弹性。生产中更常见的策略是“尽量分散,但不要因为分散失败导致服务无法启动”。

优先级与抢占

没有优先级的集群,在资源紧张时无法区分核心链路和低价值任务。建议为不同类型工作负载设置 PriorityClass:

  • platform-critical:DNS、Ingress、监控、控制面依赖。
  • business-critical:核心在线业务。
  • standard:普通服务。
  • batch-low:批处理、报表、CI。

抢占可以保护关键服务,但也可能造成低优先级任务反复被驱逐。对批处理系统,要确保任务具备可重试能力,并且不会因抢占导致数据不一致。

HPA、VPA 与集群自动扩容

HPA 解决副本数弹性,VPA 解决资源请求建议,Cluster Autoscaler 或云厂商节点自动扩容解决节点容量。三者要一起设计。

典型链路是:

  1. 流量上升,HPA 增加 Pod 副本。
  2. 新 Pod 因节点资源不足 Pending。
  3. 集群自动扩容增加节点。
  4. 调度器把 Pending Pod 放到新节点。

如果节点启动慢、镜像拉取慢、HPA 指标滞后,就会出现扩容跟不上流量的情况。关键服务可以预留缓冲容量,或使用预测型扩容策略。

VPA 在生产中建议先以 recommendation 模式运行,用它校准 requests。直接自动修改在线服务 requests 可能触发重建 Pod,需要谨慎评估。

容量水位

容量治理应关注三类水位:

  • 已请求水位:所有 Pod requests 之和与节点可分配资源的比例。
  • 实际使用水位:真实 CPU、内存、磁盘、网络使用。
  • 弹性水位:在节点故障或流量突增时还能承载多少副本。

一个常见目标是在线节点池保留 20% 到 30% 的请求余量,具体比例取决于节点扩容速度、业务峰谷、故障域设计和成本压力。对金融、支付、核心交易类业务,余量应更保守。

排障方法

当出现 Pending 或调度异常时,可以按以下路径排查:

  1. 查看 Pod Events,确认过滤失败原因。
  2. 查看 requests 是否超过节点可分配资源。
  3. 检查 nodeSelector、nodeAffinity、tolerations。
  4. 检查 PVC 是否绑定,存储类是否支持目标可用区。
  5. 检查 namespace ResourceQuota 和 LimitRange。
  6. 检查节点最大 Pod 数、CNI IP 池容量。
  7. 检查自动扩容组件日志。

总结

调度与容量治理是 K8s 生产化的底层能力。它连接成本、稳定性、发布效率和故障恢复。真正可靠的集群,不是平时节点利用率看起来漂亮,而是在资源紧张、节点故障、流量突增、批任务挤压时,仍然能让关键服务优先运行,并且让扩容链路可靠闭环。

适用场景

适合正在处理 K8s、Kubernetes, Scheduler, Capacity, HPA 相关问题的团队,用于快速建立排查路径和交付标准。

问题背景

深入理解 K8s 调度链路、资源请求、优先级、亲和性、污点容忍和容量治理,避免集群在高峰期出现 Pending、抢占和雪崩。

排查步骤

先确认影响范围和最近变更,再收集日志、配置、指标和链路数据,最后按风险从低到高执行修复。

命令示例

示例命令请替换为你的真实资源名,并使用环境变量保存账号、密码、token 等敏感信息。

风险说明

生产环境操作前需要确认备份、权限边界、变更窗口和回滚路径,避免扩大故障影响。

回滚方案

保留原配置和发布版本;如修复后指标异常,立即回退配置、镜像或数据库变更并复核日志。

交付清单

问题定位记录、关键命令、修复步骤、验证结果、后续优化建议。

!

遇到类似技术问题?

如果你的服务器、K8s、Docker、CI/CD、数据库或监控系统出现类似问题,可以提交日志和配置文件,我们帮你远程诊断。

工单 WhatsApp 联系 咨询