容器平台的资源利用率偏低,很多时候不是调度器能力不足,而是资源模型设计得过于保守。假设一台16核64GB内存的宿主机,只放了十几个Pod,CPU利用率却不到20%,常见原因是每个Pod的Request值填得过高,或者Limit值被当成调度依据。Kubernetes调度器只看Request,不看Limit,因此提升容器密度的第一步是把Request与Limit的语义彻底拆开。

一、Request与Limit如何决定容器密度
Kubernetes在调度Pod时,会计算节点上所有已绑定Pod的Request总和,并与节点的Allocatable资源进行比较。Allocatable并不是物理容量,而是节点总容量减去系统保留、Kubelet保留以及驱逐阈值之后的可用量。比如一台16核64GB的节点,如果systemReserved和kubeReserved合计预留了1核2GB,那么Allocatable大约是15核62GB。只有新Pod的Request能够被剩余Allocatable容纳时,调度器才会把它放上去。
这意味着Limit对调度没有直接影响。一个容器可以设置Request为100m CPU,Limit为2000m CPU,调度器只按100m计算节点剩余容量。如果节点上已经分配了14核Request,理论上还能继续放入多个低Request的Pod,即使这些Pod的Limit总和远超16核。这就是CPU超卖的基础。反过来,如果团队把Request设置为接近峰值使用量,节点密度就会被锁死在很低水平;如果设置得过低,又会带来资源争抢风险。合理的Request应该代表容器的常态负载,而不是峰值上限。
以Java应用为例,启动阶段CPU可能冲到1核,但稳态只需要200m。很多平台默认把Request设成500m甚至1核,导致节点只能排布十几份工作负载。通过压测确认稳态分位值后,将Request调整到300m、Limit保留1核,可以在不影响启动弹性的前提下显著提高装箱率。内存也类似,但内存不可压缩,调低Request的风险更高,需要单独设计。
二、CPU超卖:可压缩资源的安全边界
CPU是典型的可压缩资源。当多个容器同时需要CPU时,内核的CFS调度器会按权重分配时间片,而不是直接杀掉进程。Kubernetes通过cgroup的cpu.cfs_period_us和cpu.cfs_quota_us实现Limit限制。例如Limit为2000m时,一个100ms周期内容器最多使用200ms的CPU时间。如果节点整体CPU已经饱和,低优先级容器会被限流,表现为CPU Throttling。
因此CPU超卖在技术上是相对安全的:超卖过多不会导致OOM,只会增加响应延迟。但这个安全边界建立在负载错峰和可容忍延迟的基础上。如果所有Pod都是计算密集型并且同时打满,超卖3倍会把延迟拖垮。通常在线业务的CPU超卖比控制在1.5到2.5倍比较稳妥,也就是节点上所有Limit之和可以达到物理核数的1.5到2.5倍,而所有Request之和仍不超过Allocatable。这样既能吸收短时峰值,又给调度器保留了明确的基线。
下面是一个常见的资源配置片段,Request保持较低基线,Limit给出弹性空间:
apiVersion: v1
kind: Pod
metadata:
name: api-server-demo
spec:
containers:
- name: app
image: demo/api-server:latest
resources:
requests:
cpu: 300m
memory: 384Mi
limits:
cpu: 1500m
memory: 768Mi
上述配置中,调度器按300m CPU计算密度,但容器最大可占用1.5核。节点可以放入更多此类Pod,只要Requests总和不超过Allocatable,就处于受控超卖状态。如果所有Pod同时打满,节点会进入CPU饱和,但不会触发内存级灾难。因此监控CPU Throttling指标是判断超卖是否过度的重要依据,通常应保持90%以上请求未被限流。
三、内存超卖:为什么必须谨慎
内存与CPU的本质区别在于不可压缩。内存不足时,内核无法通过排队来缓解压力,只能选择回收或杀进程。Kubernetes的统一视角下,节点内存耗尽会触发OOM Killer,而OOM Killer的选择顺序由QoS等级和内存使用量共同决定。如果大量Pod的Request设置过低、实际使用又很高,节点会频繁出现OOMKilled事件,业务表现为Pod重启甚至节点抖动。
很多人误以为只要节点的内存Request总和不超过物理内存,内存就不会出问题。实际上Request只是调度基线,运行时的真实内存可能远超Request。Linux的cgroup对内存Limit的触发方式是回收失败后OOM杀容器,而不是像CPU那样限流等待。因此一旦节点上所有容器同时逼近各自的内存Limit,物理内存就会被击穿。更危险的是,如果节点系统服务或Kubelet没有足够预留,OOM Killer甚至可能杀死系统进程。
所以生产环境的内存超卖比例应该非常克制。一般建议内存Request之和不超过Allocatable的90%到95%,也就是几乎不超卖;如果业务有稳定且可预测的低峰期,可以短期允许轻微超卖,但必须配置硬驱逐水位。内存Limit可以高于Request,但要考虑实际使用是否可能长时间超过Request。对于缓存类或批处理类应用,可以使用PodDisruptionBudget减少批量驱逐风险,并通过节点压力驱逐策略提前迁移Pod。
四、QoS等级与节点压力驱逐的配合
Kubernetes为每个Pod划分QoS等级,主要依据是Request与Limit是否相等以及是否全部设置。Guaranteed等级要求所有容器的CPU和内存都同时设置Request和Limit,并且两者相等,这类Pod在OOM时最不容易被杀。Burstable等级覆盖了至少一个容器设置了Request或Limit且不完全相等的场景。BestEffort则是完全没有设置资源声明,OOM评分最高,最先被驱逐。
OOM评分的计算除了QoS等级,还考虑内存实际使用量与Request的比值。对于Burstable容器,实际内存超出Request越多,被OOM Killer选中的概率越大。这意味着即使你给容器设置了内存Limit为4GB,但Request只有256MB,当节点内存紧张时它很可能成为牺牲品。因此关键在线服务的Request不能过低,最好接近其稳定内存占用。
节点压力驱逐是比OOM更早的一道防线。Kubelet会监控memory.available、nodefs.available、imagefs.available等指标,当可用内存低于硬驱逐阈值时,立即按优先级驱逐Pod。典型配置如下:
--eviction-hard=memory.available<500Mi,nodefs.available<10%,imagefs.available<15% --eviction-soft=memory.available<1Gi --eviction-soft-grace-period=memory.available=1m30s
这段参数表示当节点可用内存低于500Mi时立即触发驱逐;当低于1Gi并持续1分30秒时也触发软驱逐。驱逐顺序同样参考Pod的QoS等级、实际内存占用和优先级。通过提前驱逐,可以避免内核OOM直接杀容器导致的状态不可控。需要注意的是,硬驱逐阈值必须低于Kubelet自身和系统进程所需的内存,否则节点可能无法稳定运行。
五、超卖配比、压测与系统防护
设计超卖策略不能只靠经验,需要在预发或灰度环境做容量验证。先确定基准:用kubectl top nodes观察节点实际CPU和内存使用率,再用kubectl describe nodes查看Allocated resources中的分配比例。如果节点Request分配率已经很高但实际使用率很低,说明Request设置偏大,存在密度优化空间。如果实际使用率已经接近90%而Request分配率并不高,说明超卖已经接近危险区。
超卖比例的常见经验值是CPU控制在Allocatable的1.5到3倍,内存严格控制不超过1.2倍,且内存超卖只适合在可快速迁移的场景中短期使用。对于有状态服务、数据库、消息队列等,建议内存完全不超卖,并设置Guaranteed QoS。对于无状态Web和API服务,可以采用Burstable级别,借助弹性伸缩和驱逐策略吸收波动。
最后还要用LimitRange和ResourceQuota在命名空间层面兜底。LimitRange可以给未显式声明资源的容器注入默认Request和Limit,避免遗漏配置;ResourceQuota可以限制整个命名空间的资源申请总量,防止单个团队过度占用集群。下面是一个LimitRange示例:
apiVersion: v1
kind: LimitRange
metadata:
name: default-resource
spec:
limits:
- default:
cpu: 1000m
memory: 1Gi
defaultRequest:
cpu: 200m
memory: 256Mi
type: Container
这个配置为新容器提供默认值,同时限制资源声明范围。综合使用Request/Limit建模、CPU弹性超卖、内存保守策略、QoS分级和驱逐水位,可以让容器密度在不牺牲稳定性的前提下提升2到3倍。核心要点是:CPU看Throttling,内存看OOM和驱逐,密度看Request分配率,三者监控到位,超卖才可控。
容器密度资源超卖Kubernetes修改时间:2026-09-26 06:20:05