【K8S系列】Kubernetes 调度与资源管理深度剖析:Requests、Limits、QoS 与 OOM
引言
Kubernetes(K8s)是一个强大的容器编排平台,它通过声明式 API 为应用提供自动调度、弹性伸缩和资源隔离能力。然而,许多生产故障(Pod OOMKilled、节点不均衡、关键服务被驱逐)往往都与requests/limits 配置不当密切相关。
本文将深入剖析 Kubernetes 在调度与资源管理上的核心机制,包括:
requests
与limits
的定义与作用- QoS 类别(Guaranteed、Burstable、BestEffort)及其驱逐机制
- OOM(Out-Of-Memory)与 Eviction 的区别与触发逻辑
- 生产环境常见问题与误区
- 最佳实践与优化策略(结合实战案例)
1. requests 与 limits:K8s 调度的基石
1.1 requests
-
定义:容器在调度时至少需要的资源(CPU、内存)。
-
作用:调度器根据 requests 计算 Pod 需要的资源,从而决定其能否放到某个节点。
- CPU requests = scheduler 用于调度的“最小保证值”。
- Memory requests = Pod 保证能获得的最小内存。
示例:
resources:requests:cpu: "200m" # 200m = 0.2 vCPUmemory: "256Mi"
1.2 limits
-
定义:容器在运行时能够使用的最大资源上限。
-
超过 limits 的表现:
- CPU:容器会被 限流(throttling),不会直接杀死。
- Memory:如果超出内存 limit → 容器触发 OOMKill。
示例:
resources:limits:cpu: "500m"memory: "512Mi"
1.3 requests vs limits 的关系
- requests ≤ limits(K8s 强制要求)
- requests 决定调度,limits 决定运行时的约束
- 生产实践:通常设置
requests = 平均用量
,limits = 峰值(合理冗余)
2. QoS 类别与驱逐策略
Kubernetes 根据 Pod 中 requests/limits 的配置,将 Pod 分为三类 QoS(Quality of Service),决定节点资源紧张时的驱逐顺序。
2.1 Guaranteed
- 条件:每个容器的
requests == limits
,且 CPU/内存都设置了。 - 特点:最高优先级,最不容易被驱逐。
- 场景:关键业务(数据库、核心微服务)。
2.2 Burstable
- 条件:至少有一个容器设置了 requests,但 requests ≠ limits。
- 特点:介于 Guaranteed 和 BestEffort 之间,资源使用灵活。
- 场景:大部分普通微服务。
2.3 BestEffort
- 条件:没有容器设置 requests/limits。
- 特点:最低优先级,节点资源不足时最先被驱逐。
- 场景:开发环境、临时批处理任务。
2.4 驱逐顺序
当节点资源不足时,驱逐优先级:
- BestEffort
- Burstable(超出 requests 且内存紧张时)
- Guaranteed(几乎最后才被驱逐)
3. OOM 与 Eviction:不一样的“被杀”
很多人容易混淆 OOMKill 与 Eviction,实际上它们的触发机制不同。
3.1 OOMKill(容器级别)
- 触发条件:容器使用内存 > limits。
- 行为:Linux cgroup 内存隔离机制触发,直接杀死容器(状态:
OOMKilled
)。 - 日志表现:
kubectl describe pod <pod>
# Events 中会显示 OOMKilled
3.2 Eviction(节点级别)
- 触发条件:节点整体内存/磁盘压力,超出 kubelet 配置的 eviction threshold。
- 行为:kubelet 按照 QoS 优先级驱逐 Pod。
- 日志表现:
kubectl describe node <node>
# Events 中会显示 "MemoryPressure" 或 "Evicted"
3.3 区别总结
特性 | OOMKill (容器) | Eviction (节点) |
---|---|---|
触发者 | Linux cgroup | kubelet |
范围 | 单个容器 | 整个节点 |
条件 | 容器内存 > limits | 节点内存/disk 不足 |
表现形式 | Pod 状态 OOMKilled | Pod 状态 Evicted |
4. 常见问题与误区
4.1 未设置 requests/limits
- 表现:调度器认为容器“零资源需求”,调度倾向于某些节点 → 节点资源倾斜。
- 风险:BestEffort QoS → 最容易被驱逐。
- 典型事故:关键 Pod 没有 requests,被驱逐导致业务中断。
4.2 requests 设置过大
- 表现:Pod 明明只需要 200m CPU,却设置了 2 核 → 调度器认为节点资源不足,Pod Pending。
- 风险:资源浪费,调度失败。
- 典型事故:CI/CD 自动化创建的 Pod 全部 Pending。
4.3 limits 设置过小
- 表现:应用有内存峰值,limits 配置过低 → 容器频繁 OOMKilled。
- 风险:应用可用性差,频繁重启。
- 典型事故:大查询时数据库容器被 OOMKill。
4.4 requests = limits(过于保守)
- 好处:Guaranteed QoS,稳定性最高。
- 风险:如果所有服务都这样配置,整体资源利用率会很低(因为 requests 过高)。
5. 最佳实践与优化策略
5.1 基于历史指标设定 requests/limits
-
使用 Prometheus + kube-state-metrics + VPA(Vertical Pod Autoscaler)收集实际使用数据。
-
经验值:
- requests = P50(中位数用量)
- limits = P95(峰值用量)
5.2 LimitRange 与 ResourceQuota
- 在命名空间内设置默认 requests/limits,防止用户忘记配置。
apiVersion: v1
kind: LimitRange
metadata:name: ns-defaults
spec:limits:- default:cpu: 500mmemory: 512MidefaultRequest:cpu: 200mmemory: 256Mitype: Container
- ResourceQuota 控制整个命名空间资源上限,避免资源抢占。
5.3 QoS 策略应用
- 核心业务:Guaranteed
- 普通服务:Burstable
- 临时任务:BestEffort(需容忍被驱逐)
5.4 Eviction 策略优化
- 配置 kubelet
--eviction-hard
/--eviction-soft
参数,合理预留节点资源。 - 配置
system-reserved
与kube-reserved
,确保节点本身稳定。
5.5 自动化与治理
- 使用 Admission Controller(OPA/Gatekeeper)强制要求所有 Pod 必须配置 requests/limits。
- 使用 VPA(垂直自动扩缩容)或 HPA(水平扩缩容)动态调整。
6. 案例分析
项目线上事故分析:
- 背景:交易网关服务容器配置
memory: 512Mi
,但高峰时瞬时内存需求达到 800Mi。 - 现象:容器频繁 OOMKilled,导致交易失败。
- 原因:limits 设置过低,且 requests = limits,QoS 虽高,但没有给出峰值冗余。
- 解决:通过历史数据分析,将
requests=500Mi
,limits=1Gi
,稳定运行,且通过 HPA 保证横向扩容。
结语
在 Kubernetes 中,调度与资源配置是稳定性的基石。
合理设置 requests/limits → 正确分配 QoS → 避免 OOM 与无序驱逐 → 提升资源利用率与业务可用性。
在实际工程中,最关键的是:
- 监控与数据驱动:基于真实指标设定 requests/limits,而不是拍脑袋。
- 策略与自动化:通过 LimitRange/ResourceQuota/OPA 保证配置合规。
- 演练与迭代:持续优化 requests/limits,避免资源浪费和业务中断。