在Kubernetes集群中,Pod的资源请求(requests)和资源限制(limits)是最基础也最容易出错的配置。很多稳定性事故的根因并不是代码缺陷,而是资源限制设置不合理:内存限制过小导致容器频繁OOMKilled,CPU限制过紧导致请求延迟飙升,或者完全没有设置requests导致调度器将大量Pod堆叠在同一节点上。理解内存与CPU在Kubernetes资源模型中的不同行为,是构建稳定集群的第一步。

一、requests与limits的调度与运行语义
Kubernetes将计算资源分为可压缩资源与不可压缩资源,CPU属于前者,内存属于后者。Pod中的每个容器都可以单独声明resources字段,其中requests表示容器启动时希望保证获得的最小资源量,limits表示容器允许使用的最大资源量。这是两个完全独立的维度:requests影响调度结果,limits影响运行时限制。
调度器在决定将Pod放置到哪个节点时,只会累加所有容器的requests值,并与节点的可分配资源进行比较。即使某个节点的实际空闲资源很多,但只要空闲资源无法满足新Pod的requests,Pod就不会被调度上去。而limits则在容器运行阶段通过内核机制强制执行:内存超限会触发OOM Killer杀掉容器,CPU超限则会通过cgroup的配额机制限制使用时间,不会直接杀死容器。
下面的YAML展示了一个同时设置内存和CPU请求与限制的Pod:
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: app
image: nginx:1.25
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "1"
这段配置表示调度时需要保证节点至少还有128Mi内存和0.25核CPU可用,而容器运行时内存最多使用512Mi,CPU最多使用1核。如果容器实际内存使用超过512Mi,内核会直接终止该容器;如果CPU使用超过1核,则会被cgroup限制在1核以内。
requests和limits之间没有强制的大小关系,可以只设置其中一个。但只设置limits而不设置requests时,Kubernetes会默认将requests的值赋值为与limits相同;只设置requests而不设置limits时,limits为空,意味着容器在运行时可以无限制地使用该资源。生产环境中建议两者都显式设置,避免隐式行为造成误解。
二、内存限制:为什么配置不当会导致OOMKilled
内存是不可压缩资源,一旦分配给进程,就不能像CPU那样通过时间片轮换暂时回收。当容器内存使用超过limits时,Linux内核的OOM Killer会直接杀死容器内占用内存最多的进程,在Kubernetes层面表现为Pod进入OOMKilled状态。这个机制简单直接,但问题在于很多应用并没有平滑的内存上界,比如带缓存的数据库、Java应用、以及内存泄漏的进程。
如果只设置了较小的内存limits,应用在启动初期可能就接近上限,一旦流量增加或缓存增长就会触发OOMKilled。此时容器会被重新拉起,又很快再次被杀,形成反复重启的循环。更隐蔽的是,如果Pod所在节点的整体内存不足,即使Pod没有超过自己的limits,也可能因为节点压力而被驱逐。Kubernetes的QoS等级会决定驱逐顺序:Guaranteed、Burstable、BestEffort,没有设置requests和limits的Pod会被最先驱逐。
对于内存限制的设置,建议先通过监控采集应用在真实负载下的内存峰值,再预留20%到30%的余量作为limits。requests可以设置为应用稳定运行时的平均内存值,既保证调度准确,又避免浪费节点资源。对于Java应用,还应关注JVM堆大小与容器内存限制的匹配,防止JVM按宿主机内存自动计算默认堆大小。下面的命令可以查看Pod的实际内存使用情况:
kubectl top pod resource-demo # 输出示例 # NAME CPU(cores) MEMORY(bytes) # resource-demo 210m 346Mi
如果观察到内存使用曲线呈现持续上涨且没有回落,很可能是内存泄漏,此时单纯调整limits只是推迟问题发生时间。正确做法是先定位泄漏点,同时可以设置合理的limits作为保护边界,避免单个容器拖垮整个节点。
三、CPU限制:可压缩资源与节流问题
与内存不同,CPU是可压缩资源。即使容器CPU使用超过limits,内核也不会杀死容器,而是通过CFS(完全公平调度器)的配额机制对容器进行节流(throttling)。在cgroup v1中,cpu.max对应cpu.cfs_quota_us和cpu.cfs_period_us的组合;在cgroup v2中,cpu.max直接表示为配额和周期。当容器在周期内消耗完配额后,剩下的时间会被强制停止运行,直到下一个周期开始。
CPU节流对延迟敏感型应用影响很大。假设一个Web服务设置了limits为500m,即每100ms周期内只能使用50ms的CPU时间。如果某次请求触发了大量计算,可能在20ms内就用光了配额,那么剩余的80ms内进程无法执行,导致请求响应时间暴涨。这种抖动在吞吐量统计中可能不明显,但在P99延迟指标上会非常刺眼。
因此,对于CPU限制的实践存在两种主流观点。一种建议是只设置CPU requests以保证调度质量,不设置CPU limits,让应用在空闲CPU上自由运行。这样能避免不必要的节流,但对多租户集群来说,某个失控应用可能占用整个节点的CPU,影响其他Pod。另一种建议是设置相对宽松的CPU limits,例如将limits设为requests的2到4倍,既能提供一定保护,又能减少正常流量下的节流概率。
如果已经出现CPU节流,可以通过cadvisor指标container_cpu_cfs_throttled_seconds_total来确认。持续非零说明确实存在节流,需要调高limits或优化代码。下面的YAML展示了只设置requests不设置limits的写法:
apiVersion: v1
kind: Pod
metadata:
name: cpu-no-limit
spec:
containers:
- name: app
image: myapp:latest
resources:
requests:
cpu: "500m"
memory: "256Mi"
这种配置下,容器最低可以保证500m CPU,在节点有空闲CPU时也可以使用超过500m,但不会受到强制上限。代价是一旦节点出现CPU压力,Burstable QoS的Pod会先于Guaranteed Pod被驱逐,因此仍需结合监控和告警来控制风险。
四、生产环境最佳实践与配额管理
在团队规模较大或命名空间较多的场景中,仅靠开发者自觉设置requests和limits并不现实。Kubernetes提供了LimitRange和ResourceQuota两个内置对象来统一约束资源行为。LimitRange可以对命名空间内的Pod、容器、PVC等对象设置默认的requests和limits,同时还能够限制单个容器可声明的最大值和最小值。
下面的LimitRange示例为每个容器设置默认requests为100m CPU和128Mi内存,默认limits为500m CPU和512Mi内存,并禁止容器声明超过2核CPU或1Gi内存的limits:
apiVersion: v1
kind: LimitRange
metadata:
name: default-resource-limits
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
max:
cpu: "2"
memory: "1Gi"
min:
cpu: "50m"
memory: "64Mi"
ResourceQuota则从命名空间整体层面限制资源总量,防止某个团队占用过多集群资源。例如限制整个命名空间的CPU requests总和不超过10核,内存requests总和不超过20Gi,同时也可以限制PVC数量、Service数量等对象配额。下面是一个ResourceQuota示例:
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
spec:
hard:
requests.cpu: "10"
requests.memory: "20Gi"
limits.cpu: "20"
limits.memory: "40Gi"
persistentvolumeclaims: "20"
配合使用LimitRange和ResourceQuota后,开发者提交的资源声明会被自动补全默认值,超出范围的配置会被拒绝,整个命名空间的资源使用也被限制在可管理的规模内。管理员还可以通过kubectl describe resourcequota查看当前配额使用情况。
监控是资源管理闭环中不可缺少的一环。建议重点关注节点内存压力、Pod重启次数、CPU节流比例、实际使用量与requests的比值等指标。例如节点内存使用率持续超过85%时,应及时扩容或迁移Pod;Pod实际使用量长期低于requests的50%,则说明requests设置过高,造成资源浪费。通过持续调整,可以让集群资源利用率维持在既安全又高效的水平。
最后还有几个常见误区需要澄清:第一,认为requests只在调度时起作用,后续节点资源变化不会影响Pod。实际上当节点出现资源压力时,requests和limits会共同决定QoS等级和驱逐顺序。第二,认为内存limits越大越好。过大的limits可能导致节点过度分配,当所有Pod同时上涨时节点内存耗尽,反而引发更大范围驱逐。第三,认为CPU limits可以完全避免资源争抢。CFS只限制CPU使用时间,并不隔离缓存、内存带宽等共享资源,真正需要强隔离时应该考虑使用容器运行时级别的更精细控制。
Kubernetes资源限制Pod内存限制CPU请求限制修改时间:2026-08-20 11:57:12