Kubernetes调度进阶:从基础Pod分配到精细化资源优化的实战策略

loong
2026-01-13 / 0 评论 / 16 阅读 / 正在检测是否收录...

Kubernetes调度进阶:从基础Pod分配到精细化资源优化的实战策略

你有没有遇到过这种情况?明明集群还有不少空闲资源,新部署的Pod却卡在Pending状态,日志里冷冰冰地提示Insufficient cpu。或者,某个节点负载突然飙升,导致上面的应用响应变慢,而其他节点却闲得发慌。

这通常不是资源真的不够,而是调度器“看不见”或者“不会用”。默认的Kubernetes调度器(kube-scheduler)遵循一套基础规则,但在生产环境中,这套规则往往不够用。今天,我们就来聊聊如何超越默认调度,通过高级策略和优化实践,真正驾驭集群的资源分配。

默认调度器:它做了什么,又没做什么?

简单来说,kube-scheduler的工作分两步:过滤(Filtering)打分(Scoring)

过滤阶段,它会筛掉所有不满足硬性条件的节点,比如资源不足、节点Selector不匹配、污点容忍度不符等。剩下的节点进入打分阶段,调度器根据资源平衡、镜像 locality 等策略给每个节点打分,最后选择得分最高的。

听起来挺合理,对吧?但问题就藏在细节里。

默认的调度策略主要关注即时请求(Request)。你为Pod设置了requests.cpu: 500m,调度器就认为它需要占用500毫核。但实际运行时,这个Pod可能只用100m,那多出来的400m就被“浪费”地锁定了,其他Pod无法使用。反之,一个突发流量的Pod可能瞬间需要800m,但因为Request只写了500m,它会被限制,导致性能下降。

这种基于静态Request/Limit的模型,是很多资源利用率低下和性能问题的根源。

超越默认:让调度更“智能”的策略

1. 用好节点亲和与反亲和:不只是“靠近”,更是“远离”

节点亲和性(Node Affinity)大家可能都用过,比如把Web服务调度到带disktype: ssd标签的节点上。但我想强调的是Pod间反亲和性(Pod Anti-Affinity),它对于实现高可用至关重要。

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels:
                app: my-critical-app
            topologyKey: kubernetes.io/hostname

上面这个配置意味着:同一个my-critical-app的多个副本,绝不能被调度到同一台物理主机上。这样,即使一台主机宕机,你的服务依然有副本在其他节点上运行。把topologyKey换成failure-domain.beta.kubernetes.io/zone,就能实现跨可用区部署。

坦白讲,对于核心服务,我几乎都会加上反亲和规则。这是用调度策略换取稳定性的最有效方式之一。

2. 污点与容忍度:为节点划分“专属区域”

你可以把污点(Taint)想象成节点的“气味”,只有带有相应容忍度(Toleration)的Pod才能“忍受”并调度上去。

一个经典场景:设立专属节点组。

# 给一组GPU节点打上污点
kubectl taint nodes node-group-gpu special-hardware=gpu:NoSchedule

# 在你的AI训练Job的PodSpec中加上容忍度
spec:
  tolerations:
  - key: "special-hardware"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"

这样,只有明确声明需要GPU的任务才会被调度到这些昂贵且稀缺的节点上,避免了普通Pod误入,最大化专用资源的效益。

3. 资源请求与限制:别猜了,用数据说话

这是优化资源利用率的核心,也是最容易出错的地方。我的建议是:

  • 不要拍脑袋设置Request/Limit。先让应用带一个较宽松的Limit(防止容器爆炸)但较低的Request运行一段时间。
  • 利用监控数据。通过Metrics Server、Prometheus等工具,收集容器实际的CPU/内存使用量(特别是P95/P99值)。
  • 逐步调整。根据历史数据,将Request设置到接近P95使用量的水平,为突发留出一些缓冲(Limit可以更高)。这样既能保证调度效率,又能提升节点装箱密度。

说实话,我看到太多团队把Request和Limit设成一样的值,这完全失去了Limit防止资源耗尽的意义,也让调度器过于悲观。

进阶武器:调度框架与自定义调度器

当内置规则无法满足你时,Kubernetes提供了更强大的扩展能力。

调度框架(Scheduling Framework) 允许你以插件形式在调度周期的各个扩展点(如过滤前、打分后)注入自定义逻辑。比如,你可以写一个插件,优先将Pod调度到已经缓存了其所需大镜像的节点上,加速启动。

如果需求非常独特,比如需要根据实时商品价格选择最便宜云厂商的节点,或者实现复杂的批量作业调度,那么自定义调度器是最终选择。你可以自己编写一个调度程序,与默认调度器并存,用spec.schedulerName来指定Pod由谁调度。

不过,走这条路需要深厚的Kubernetes内部知识,维护成本也高,除非必要,一般不建议轻易尝试。

实战优化:从策略到落地

理论说了不少,分享一个简化版的真实案例。

我们有一个混合了在线服务和离线批处理任务的集群。最初所有Pod混部,在线服务经常被批处理任务抢资源,导致延迟毛刺。

我们的优化步骤:

  1. 划分节点池:通过污点,创建dedicated-onlinededicated-batch两个节点组。
  2. 精细化资源画像:为所有在线服务分析一周的监控数据,基于P99使用量设置Request,Limit设为Request的1.5倍。批处理任务则采用较低的Request(保证能调度),但较高的Limit(允许突发使用空闲资源)。
  3. 启用集群自动伸缩:为批处理节点池配置Cluster Autoscaler,白天任务多时自动扩容,夜间自动缩容。
  4. 引入优先级与抢占:为在线服务设置更高的PriorityClass,确保在资源紧张时,低优先级的批处理任务Pod可以被驱逐,为在线服务让路。

这一套组合拳下来,在线服务的P99延迟下降了40%,集群整体平均资源利用率从35%提升到了接近60%,而且批处理任务的完成时间并没有显著增加。

写在最后

Kubernetes的高级调度和资源优化,不是一个开关或者一个银弹。它是一个持续迭代的过程,核心在于更精确地描述你的工作负载需求,并让调度器理解你的业务优先级

从今天就可以开始做的是:检查你的核心服务是否配置了反亲和以实现高可用;回顾一下主要应用的Request/Limit设置,是不是该用监控数据校准一下了。

调度策略的终点,是让基础设施的复杂性对业务透明,让合适的负载,在合适的时间,运行在合适的位置上。这条路没有终点,但每走一步,都能让你的系统更稳健、更高效。

你的集群里,最棘手的调度问题是什么?是资源利用率上不去,还是应用稳定性受影响?不妨从一两个具体的点开始优化吧。

0