很多人学 Kubernetes 时,最容易“看懂 YAML,却看不懂资源行为”。
比如:
- 为什么 Pod 能调度上去,但跑起来很卡?
- 为什么明明限制了 CPU,服务只是变慢,却没有直接挂掉?
- 为什么内存一超就
OOMKilled? - 为什么有的 Pod 在节点压力下会优先被驱逐?
这些问题背后,几乎都和 requests、limits、QoS 有关。
这一章我们把这条线完整串起来:资源申请怎么影响调度,资源上限怎么影响运行,QoS 又怎么影响驱逐顺序。
1. Request 与 Limit 的含义与区别
Kubernetes 允许你为容器声明资源需求。官方文档说明:当你为 Pod 中的容器设置资源 request 时,kube-scheduler 会依据 request 决定 Pod 可以放到哪些节点;而 limits 则用于约束容器运行时可使用的资源上限。::cite[327]
1.1 最简单的理解
- request:调度阶段的“保底申请”
- limit:运行阶段的“使用上限”
也就是说:
- 调度器主要看
request; - 容器运行时是否会被限制,主要看
limit。
1.2 一张表理解 request 和 limit
| 维度 | request | limit |
|---|---|---|
| 作用阶段 | 调度阶段 | 运行阶段 |
| 关注对象 | 调度器是否允许放到某节点 | 容器最多能用多少 |
| CPU 行为 | 保证可分配下限 | 超过上限会被节流 |
| 内存行为 | 影响节点放置 | 超过上限可能触发 OOM |
| 是否建议设置 | 建议设置 | 多数生产场景建议设置 |
1.3 一个标准示例
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: app
image: nginx:1.27
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
这段配置可以理解为:
- 调度器会按 250m CPU + 256Mi 内存 去找节点;
- 容器运行后,最多只能使用 500m CPU + 512Mi 内存。
2. CPU 与内存资源如何被调度与限制
2.1 CPU:主要体现为“可调度 + 节流”
官方文档指出:当你为容器配置 CPU request 和 CPU limit 时,容器在系统有空闲 CPU 的情况下,至少能获得 request 对应的 CPU 份额;同时,容器不能超过设定的 CPU limit。::cite[328]
换句话说:
- 调度时,CPU request 参与节点筛选;
- 运行时,CPU limit 决定最多能跑多快。
如果一个服务 CPU 经常打满、响应变慢,但进程并没有退出,常见原因之一就是:被 CPU limit 节流了。
2.2 内存:主要体现为“可调度 + OOM 风险”
内存和 CPU 最大的不同在于:内存超限的代价通常更重。
官方资源管理文档说明,Pod 的资源分配同样基于 request,而运行期会受 limit 约束。对内存来说,一旦进程实际占用持续超过 limit,就更容易被内核 OOM 处理,最终体现为容器退出或 OOMKilled。::cite[327]
所以你会发现:
- CPU 超限:常常是变慢;
- 内存超限:常常是直接被杀。
2.3 一个便于记忆的对比
| 资源 | request 影响什么 | limit 影响什么 | 超限典型表现 |
|---|---|---|---|
| CPU | 是否能调度到节点 | 最大可用 CPU | throttling,变慢 |
| Memory | 是否能调度到节点 | 最大可用内存 | OOMKilled,重启 |
3. 实操:分别观察 request 与 limit
3.1 创建一个 Burstable Pod
apiVersion: v1
kind: Pod
metadata:
name: burstable-demo
spec:
containers:
- name: app
image: nginx:1.27
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
应用资源:
kubectl apply -f burstable-demo.yaml
查看详细信息:
kubectl describe pod burstable-demo
你会看到:
- requests 被记录下来,供调度和 QoS 使用;
- limits 被记录下来,供运行时限制使用。
3.2 创建一个 Guaranteed Pod
apiVersion: v1
kind: Pod
metadata:
name: guaranteed-demo
spec:
containers:
- name: app
image: nginx:1.27
resources:
requests:
cpu: "500m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "256Mi"
在这个例子里,CPU 和内存的 request 与 limit 完全相等,因此它会进入 Guaranteed QoS。
3.3 创建一个 BestEffort Pod
apiVersion: v1
kind: Pod
metadata:
name: besteffort-demo
spec:
containers:
- name: app
image: nginx:1.27
这个 Pod 没有设置任何 CPU / 内存 request 和 limit,因此是 BestEffort。
4. QoS 分类:Guaranteed、Burstable、BestEffort
Kubernetes 会根据 Pod 中各容器声明的 CPU / 内存 request 与 limit,为 Pod 自动分配 QoS 等级。官方文档说明,这个分类会影响节点资源不足时的驱逐决策。::cite[132]
4.1 Guaranteed
满足条件:Pod 内每个容器都同时设置了 CPU 和内存 request / limit,且 request 必须分别等于 limit。 这是官方定义 Guaranteed QoS 的条件。::cite[132]
适合场景:
- 数据库
- 消息队列
- 强依赖稳定资源的核心服务
特点:
- 资源边界最明确;
- 在资源压力下通常最晚被驱逐。
4.2 Burstable
满足条件:至少有一个容器设置了 request 或 limit,但不满足 Guaranteed 条件。 官方示例中,设置了 request 和 limit 但两者不相等的 Pod,会被判定为 Burstable。::cite[133]
适合场景:
- 大多数 Web 服务
- 普通业务 API
- 可水平扩展的无状态服务
特点:
- 比 BestEffort 更稳;
- 配置弹性更大;
- 生产环境最常见。
4.3 BestEffort
满足条件:Pod 中所有容器都没有设置任何 CPU / 内存 request 和 limit。 官方文档明确指出,这种情况下 Pod 的 QoS 为 BestEffort。::cite[133]
适合场景:
- 临时测试
- 低价值批处理
- 演示环境
特点:
- 最容易被驱逐;
- 资源不可预测;
- 不适合关键生产业务。
4.4 一张表记住三类 QoS
| QoS 类别 | 条件 | 稳定性 | 典型用途 |
|---|---|---|---|
| Guaranteed | 每个容器 CPU/内存 request=limit | 最高 | 核心状态型服务 |
| Burstable | 设置了资源,但不满足 Guaranteed | 中等 | 普通生产服务 |
| BestEffort | 什么都不配 | 最低 | 临时测试任务 |
5. OOM、驱逐与资源配置误区
5.1 OOM 不等于调度失败
很多初学者会混淆两个阶段:
- 调度失败:Pod 没放上节点;
- OOMKilled:Pod 已经在节点上运行了,但运行中内存超限或发生内存压力。
前者是调度问题,后者是运行时资源问题。
5.2 驱逐和 QoS 有直接关系
官方 QoS 文档说明:Kubernetes 依赖 QoS 分类,在节点资源不足时决定优先驱逐哪些 Pod。通常来说,BestEffort 最容易被驱逐,Burstable 次之,Guaranteed 通常最靠后。::cite[132]
所以 QoS 不是“考试概念”,而是会直接影响线上稳定性。
5.3 误区一:只配 limit,不配 request
这是很常见的错误。
问题在于:
- 调度器核心看的是 request;
- 如果 request 过低或缺失,Pod 可能被放进一个并不适合长期承载它的节点;
- 运行期一旦真实负载上来,就容易出现资源争抢、延迟抖动,甚至被驱逐。
5.4 误区二:把 request 直接配成峰值
如果把 request 配得过大,调度器会认为这个 Pod 需要很多资源,从而导致:
- 节点可选范围变小;
- 集群利用率下降;
- Pod 更容易 Pending。
所以 request 应该更接近稳定运行所需值,而不是盲目按理论峰值填写。
5.5 误区三:内存 limit 配太紧
内存和 CPU 不一样。
CPU 被卡住,多数情况下只是慢;但内存 limit 过紧,业务稍一抖动就可能直接 OOM。对于有缓存、JVM、Go 堆增长、批量读写峰值的应用,尤其要留足余量。
5.6 误区四:生产环境大量使用 BestEffort
BestEffort 最大的问题不是“省事”,而是不可控。
一旦节点资源吃紧,这类 Pod 往往最先被牺牲。因此,正式环境里至少应该为关键业务配置 request,避免完全裸奔。
6. 实操:快速查看 QoS 与资源声明
6.1 查看 Pod 的 QoS
kubectl get pod guaranteed-demo -o yaml
你会在状态里看到:
status:
qosClass: Guaranteed
6.2 对比三个示例 Pod
kubectl get pod guaranteed-demo burstable-demo besteffort-demo -o custom-columns=NAME:.metadata.name,QOS:.status.qosClass
你会得到类似结果:
NAME QOS
guaranteed-demo Guaranteed
burstable-demo Burstable
besteffort-demo BestEffort
6.3 查看资源声明
kubectl describe pod burstable-demo
重点关注:
- Requests
- Limits
- QoS Class
- Events
7. 生产环境里的配置建议
7.1 无状态服务
推荐从 Burstable 起步:
- request 按稳定期负载设置;
- limit 预留突发空间;
- 配合 HPA/VPA 或监控持续调整。
7.2 核心状态服务
更适合 Guaranteed:
- 资源更稳定;
- 更不容易在压力下被驱逐;
- 更利于做容量规划。
7.3 不要靠“感觉”配资源
更靠谱的方式是:
- 先基于压测和监控给出初值;
- 观察 CPU 使用率、内存峰值、重启次数、延迟抖动;
- 再持续修正 request / limit。
8. 本章小结
把这一章压缩成几句话:
- request 主要影响调度,limit 主要影响运行。
- CPU 超限更像变慢,内存超限更像被杀。
- QoS 由 request / limit 组合自动决定。
- 节点压力下,QoS 会影响驱逐优先级。
- 生产环境最常见的是 Burstable,核心服务常用 Guaranteed。
只要你把 request、limit、QoS 这三者串起来,后面再看驱逐、配额、优先级时,就会容易很多。
📝 版权声明:本文为原创技术博客,转载请注明出处。
如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!