Kubernetes QoS(Quality of Service,服务质量)是 Kubernetes 根据 Pod 中容器的 requests 和 limits 配置,对 Pod 进行分类的一套机制。
它主要用于:
Kubernetes 原生 Pod QoS 主要分为三类:
Guaranteed
Burstable
BestEffort可以先用一句话理解:
Guaranteed:每个容器的 CPU、内存 request 和 limit 都相等
Burstable:配置了部分资源,但不满足 Guaranteed
BestEffort:所有容器都没有配置 requests 和 limits注意:Kubernetes QoS 不是网络带宽 QoS,也不是应用 SLA。它主要是容器资源配置和节点资源压力处理机制。
“QoS”这个词容易产生歧义。
Kubernetes Pod QoS 主要关注:
CPU
Memory
资源 requests/limits
节点资源压力
容器运行时资源隔离
Pod 驱逐倾向它不直接表示:
接口响应时间
SLA/SLO
网络优先级
请求成功率
业务重要性
用户体验例如,一个 Pod 被归类为 Guaranteed,并不代表:
QoS 只是资源保障模型的一部分。
节点资源有限,而 Pod 的资源需求和实际使用量可能不同。
例如一个节点内存紧张:
节点总内存:32Gi
多个 Pod 实际使用量超过预期
节点进入 MemoryPressureKubernetes 需要判断:
优先处理哪些 Pod?
哪些 Pod 更应该保留?
哪些 Pod 的资源声明不完整?QoS 可以帮助 Kubernetes 对 Pod 进行资源优先级区分。
粗略理解:
Guaranteed:资源边界最明确,通常更受保护
Burstable:有一定资源保障,但可能存在突发使用
BestEffort:没有资源声明,通常最容易受到影响但真正的驱逐决策还会结合:
所以不能简单认为:
QoS 等级 = 绝对驱逐顺序一个 Pod 被归为 Guaranteed,通常需要满足:
requests 和 limitsrequests 和 limits示例:
QoS:
Guaranteed如果 Pod 中有多个容器,则每个容器都必须满足条件:
只要其中一个容器不满足,整个 Pod 就不是 Guaranteed。
即使 Pod 是 Guaranteed,也不一定拥有独占 CPU。
如果需要 CPU 独占,通常还要结合:
requests.cpu == limits.cpu例如:
比下面这种配置更可能获得整数 CPU 绑定机会:
只要 Pod 至少配置了一部分资源,但不满足 Guaranteed 条件,通常就是 Burstable。
示例:
这里:
CPU request:250m
CPU limit:1
内存 request:512Mi
内存 limit:1Gi由于 request 小于 limit,所以是:
Burstable它表示:
平时至少需要一部分资源,
在资源允许时可以突发使用更多资源。这是生产环境中最常见的 QoS 类型。
如果 Pod 中所有容器都没有配置 CPU 和内存的 request、limit,则是 BestEffort。
示例:
或者:
resources: {}QoS:
BestEffort适合:
可以用下面的决策过程理解。
是 -> BestEffort
否 -> 继续判断否 -> Burstable
是 -> 继续判断是 -> Guaranteed
否 -> Burstable简化为:
全部没有资源声明 -> BestEffort
全部容器 CPU/Memory 的 request=limit
且 request/limit 都存在 -> Guaranteed
其他情况 -> Burstable注意:
输出示例:
Guaranteed批量查看:
kubectl get pods -n production \
-o custom-columns='NAME:.metadata.name,QOS:.status.qosClass'kubectl get pod <pod-name> 重点查看:
kubectl describe pod <pod-name> -n <namespace>重点关注:
QoS Class
OOMKilled
Evicted
MemoryPressure
FailedScheduling
Restart Countkubectl describe node <node-name>查看:
Conditions:
MemoryPressure
DiskPressure
PIDPressurerequests 主要影响:
例如:
requests:
cpu: "500m"
memory: "512Mi"调度器会按照:
500m CPU
512Mi 内存评估节点是否有足够资源。
limits 主要影响:
CPU limit 超过时通常:
CPU throttling内存 limit 超过时可能:
OOMKill更容易得到:
Guaranteed通常得到:
Burstable当节点发生内存压力时,kubelet 可能驱逐 Pod。
可以粗略理解为:
BestEffort 通常风险最高
Burstable 根据实际使用量和 request 判断
Guaranteed 通常相对更受保护对于 Burstable Pod,还要看:
实际使用量是否超过 request例如:
Pod A:request 512Mi,实际使用 2Gi
Pod B:request 512Mi,实际使用 400Mi在内存压力下,Pod A 通常比 Pod B 更容易受到影响,因为它超过了自己的 request 更多。
节点磁盘压力可能由以下内容造成:
emptyDirQoS 不是磁盘治理的全部,还需要配置:
并监控:
DiskPressure
节点文件系统使用率
容器日志增长速度
emptyDir 使用量节点 PID 耗尽时,Pod 也可能受到影响。
这不完全由 CPU/内存 QoS 解决,需要关注:
pidsLimitPIDPressure这是生产排障中非常重要的一点。
通常表示容器或其 cgroup 超过内存限制:
容器内存超过 memory limit查看:
kubectl describe pod <pod-name> -n <namespace>常见输出:
Reason: OOMKilled
Exit Code: 137表示 kubelet 因为节点整体资源压力驱逐 Pod:
节点内存、磁盘或 PID 压力过大常见原因:
MemoryPressure
DiskPressure
PIDPressurePod 可能显示:
Reason: EvictedQoS 不会直接制造 OOMKill,也不会保证不被 Eviction。
它主要影响:
在节点资源压力下,Pod 的相对处理优先级和资源保护程度CPU 资源不足时,容器通常不会像内存超限那样直接退出,而是:
被限制使用 CPUCPU limit 较低可能造成:
例如:
requests:
容器可以在节点有空闲 CPU 时突发到 1 CPU,但不能把这种突发能力当作稳定保证。
例如:
requests:
它的 CPU 使用边界清晰,资源竞争行为更可预测。
但如果要实现真正的 CPU 独占,还需要:
整数 CPU
CPU Manager static
合适的节点配置BestEffort 容器没有 request 和 limit,通常只能使用节点剩余 CPU。
节点繁忙时,运行性能可能明显下降。
HPA 通过 CPU 或内存利用率扩缩容时,通常以 request 作为基准。
例如:
resources:
requests:
cpu: "250m"实际使用:
500m相对利用率大致是:
500m / 250m = 200%如果 request 设置为:
requests:
cpu: "1"相同实际使用量的利用率变成:
500m / 1 = 50%因此:
request 过小 -> HPA 可能过于频繁扩容
request 过大 -> HPA 可能扩容过慢QoS 本身不决定 HPA,但资源配置会同时影响:
生产环境不能为了获得 Guaranteed,盲目把 request 设置得很大,否则可能导致 HPA 失真和调度资源浪费。
VPA 可以根据历史使用量建议或调整:
requests
limits常见组合:
LimitRange:设置边界和默认值
VPA:根据监控数据生成资源建议
人工审核:确认是否适合生产
Deployment:应用最终资源配置需要关注:
Off 或 Recommendation 模式QoS 和 Pod Priority 是不同概念。
| 机制 | 作用 |
|---|---|
| QoS Class | 描述资源配置和资源压力下的保护程度 |
| PriorityClass | 调度排序和抢占优先级 |
| PDB | 主动中断保护 |
| ResourceQuota | Namespace 总量 |
| LimitRange | 单对象资源边界 |
例如:
Pod A:Guaranteed,Priority 普通
Pod B:Burstable,Priority 很高Pod B 仍可能因为高 Priority 获得更高的调度和抢占优先级。
所以不能简单认为:
Guaranteed 一定比所有 Burstable 优先生产环境要同时设计:
QoS
PriorityClass
ResourceQuota
PDB一个关键服务可能配置:
它可能具有:
QoS:Guaranteed
Priority:production-critical这表示:
但也需要注意:
常见选择:
Guaranteed 或 Burstable示例:
示例:
多数普通在线服务会使用 Burstable。
通常使用:
Burstable示例:
原因:
还应结合:
通常使用:
Burstable或者对关键节点组件使用更严格的资源配置。
DaemonSet 要特别关注总量:
每 Pod request × 节点数量如果每个节点的 Agent 都配置很大,扩容节点会同步增加资源消耗。
常见选择:
Guaranteed示例:
但是否使用 Guaranteed,需要结合:
QoS 不能代替数据库高可用。
可以使用:
Burstable甚至对一次性测试工作负载使用:
BestEffort但不要让测试环境中的 BestEffort 配置直接复制到生产。
特点:
QoS:Guaranteed适合:
注意:
特点:
QoS:Burstable适合:
特点:
QoS:BestEffort适合:
不适合:
两个容器都满足 request 等于 limit,因此 Pod 可以保持:
Guaranteed如果 proxy 改成:
整个 Pod 就通常变成:
Burstable这说明:
QoS 是 Pod 级别的结果,不是只看主业务容器。特点:
QoS:Burstable适合:
如果任务允许被低优先级处理,可以进一步设置较低的 PriorityClass。
GPU 资源通常要求:
requests.nvidia.com/gpu == limits.nvidia.com/gpu但由于 CPU 和内存 request/limit 不相等,这个 Pod 通常不是 Guaranteed,而是:
Burstable如果希望 QoS 为 Guaranteed,CPU 和内存也需要 request 等于 limit。
LimitRange 可以给 Pod 注入默认资源:
如果用户提交:
containers:
- name: app
image: nginx:1.27LimitRange 可能注入:
最终 Pod 通常成为:
Burstable如果配置:
则未显式配置资源的容器可能得到 request 等于 limit,从而更接近:
Guaranteed但生产环境不要仅为了获得 Guaranteed 就把默认 request 设置得很大,否则可能导致:
ResourceQuota 可以限制 Namespace 的资源总量:
QoS 与配额之间的关系:
requests.cpu 和 requests.memory 配额,但可能仍消耗 Pod 数量配额生产环境应同时看:
QoS 分布
requests 总量
limits 总量
实际使用量Pod QoS 是 Pod 级别结果,但资源是按容器声明的。
例如:
app:
CPU request 1,limit 1
内存 request 1Gi,limit 1Gi
整个 Pod 是:
Guaranteed但调度资源大致为:
CPU:1.1
内存:1.125Gi因此即使 Pod 是 Guaranteed,也不能只看主容器资源。
还要关注:
emptyDir 内存Init Container 会影响 Pod 的资源计算和整体行为。
示例:
需要注意:
生产环境应对 Init Container 单独压测和评估。
自动注入 Sidecar 后,Pod 资源和 QoS 可能发生变化。
例如原业务容器:
注入 Sidecar 后:
由于 Sidecar 的 request 不等于 limit,整个 Pod 通常变成:
Burstable这可能影响:
生产中需要明确:
Sidecar 是否有资源默认值
Sidecar 是否会改变 QoS
Sidecar 是否计入 HPA 资源使用
Sidecar 是否造成 CPU throttling全部使用 Guaranteed 的问题:
Guaranteed 应用于:
真正需要稳定资源边界的工作负载而不是所有服务。
生产核心服务通常至少应该是:
Burstable并显式声明:
resources:
requests:
limits:对于大多数普通服务:
通常是较平衡的起点:
最终数值仍然要依据实际监控和压测调整。
例如:
核心支付服务:Guaranteed + 高 Priority
普通 API:Burstable + 普通 Priority
批处理:Burstable + 低 Priority
临时调试:BestEffort + 默认 Priority但应严格限制高 Priority 的使用权限。
错误。
Guaranteed 通常更受保护,但以下情况仍可能受到影响:
不准确。
合理配置的 Burstable Pod 可以非常稳定,很多生产在线服务都使用 Burstable。
稳定性取决于:
更准确地说:
BestEffort Pod 中没有 CPU 和内存 request/limit如果 LimitRange 自动注入了资源,Pod 就不再是 BestEffort。
QoS 和 PriorityClass 不同。
QoS:资源配置和压力处理
PriorityClass:调度和抢占错误。
必须检查:
不能。
QoS 不能替代:
kubectl get pod <pod-name> 检查每个容器:
resources:
requests:
limits:搜索:
OOMKilled
Evicted
MemoryPressure
DiskPressure
PIDPressure如果使用 Prometheus,可以关注:
rate(container_cpu_cfs_throttled_seconds_total[5m])还可以观察:
rate(container_cpu_usage_seconds_total[5m])将 throttling、CPU 使用量和应用延迟关联起来分析。
统计每个 Namespace 的:
分类:
核心在线服务
普通在线服务
批处理
DaemonSet
数据库
例如:
核心服务:Guaranteed 或高质量 Burstable
普通服务:Burstable
批处理:Burstable + 低 Priority
调试任务:BestEffort防止新 Pod 完全没有资源配置。
防止某个团队消耗整个集群。
例如强制:
生产容器必须声明 CPU request
生产容器必须声明内存 request
不允许使用 latest
不允许使用 BestEffort建议:
开发环境
预生产环境
单个生产 Namespace
同类生产 Namespace
全量推广根据数据调整:
requests
limits
LimitRange 默认值
ResourceQuota
可能得到:
Guaranteed适合资源需求稳定、对节点压力敏感的关键服务。
可能得到:
Burstable适合大多数 Web/API 服务。
可能得到:
Burstable适合任务型工作负载。
resources: {}可能得到:
BestEffort只建议用于非生产临时任务。
Kubernetes Pod QoS 是根据容器资源配置生成的资源服务质量分类:
Guaranteed:
它主要影响:
资源调度和资源声明
节点资源压力下的处理倾向
QoS 和驱逐判断
资源治理和运维分析生产环境推荐:
同时配合:
最重要的理解是:
QoS 不是业务 SLA,
Guaranteed 不是绝对高可用,
Burstable 不是不稳定,
BestEffort 不是完全不能使用。正确的生产策略不是让所有 Pod 都变成 Guaranteed,而是根据业务重要性、资源稳定性、故障容忍度和成本目标,为不同工作负载选择合适的 QoS,并用真实监控数据持续校准资源配置。 还有一些更容易被误解、但对生产排障很重要的细节。前面的内容已经覆盖主体,下面补充“高级边界”和几个需要精确理解的地方。
Pod QoS 分类主要依据:
CPU request/limit
Memory request/limit以下资源不会单独决定 Pod 是 Guaranteed、Burstable 还是 BestEffort:
ephemeral-storage
GPU
HugePages
自定义扩展资源例如:
即使 ephemeral-storage 的 request 和 limit 不相等,只要 CPU 和内存满足 Guaranteed 条件,Pod 仍可能属于 Guaranteed。
但是,这不代表临时存储、GPU 或 HugePages 没有限制,而是它们不直接决定传统 QoS 分类。
判断 QoS 时不能只看:
spec.containers还要检查:
spec.initContainers如果一个业务容器满足:
但 Init Container 配置成:
由于 Init Container 的 request 和 limit 不相等,整个 Pod 可能不再是 Guaranteed。
此外,Init Container 还会影响 Pod 的有效调度资源。其资源需求不能只简单理解为与业务容器全部相加,通常需要考虑:
普通容器资源总和
与 Init Container 中最大资源需求
取较大值因此,Init Container 不能被视为“只运行几秒,所以资源可以忽略”。
Service Mesh、日志 Agent、配置同步容器等自动注入的 Sidecar,可能改变整个 Pod 的 QoS。
原始业务容器:
注入的 Sidecar:
最终结果通常是:
原业务容器:满足 Guaranteed
Sidecar:不满足 Guaranteed
整个 Pod:Burstable生产环境需要检查 Admission Webhook 注入后的最终 Pod:
kubectl get pod <pod-name> 重点确认:
QoS 和业务优先级不是同一个概念。
例如:
Pod A:Guaranteed,PriorityClass=普通
Pod B:Burstable,PriorityClass=高Pod B 仍可能在调度和抢占上拥有更高优先级。
可以把几个机制区分为:
| 机制 | 主要职责 |
|---|---|
| QoS | 资源配置分类和压力处理 |
| PriorityClass | 调度顺序和抢占 |
| PDB | 主动中断保护 |
| ResourceQuota | Namespace 总量 |
| LimitRange | 单对象资源边界 |
| NetworkPolicy | 网络访问控制 |
生产环境中,不要通过把所有 Pod 设为 Guaranteed 来表达业务重要性。业务重要性应使用:
priorityClassName: production-critical并通过 RBAC 和策略限制其使用。
很多资料会简化成:
BestEffort -> Burstable -> Guaranteed但实际驱逐还会考虑:
对于内存压力,Burstable Pod 还要关注:
实际内存使用量 / memory request例如:
Pod A:request 512Mi,实际使用 2Gi
Pod B:request 512Mi,实际使用 400MiPod A 更可能被优先处理,因为它明显超过了自己的 request。
因此生产排障不能只看 QoS,还要同时查看:
request
实际使用量
PriorityClass
节点压力通常表现为:
容器超过自己的 memory limit查看:
kubectl describe pod <pod-name> -n <namespace>常见结果:
Reason: OOMKilled
Exit Code: 137表示节点整体内存不足,可能由 Linux 内核直接触发 OOM Killer。
此时可能出现:
排查节点级问题需要查看:
因此:
memory limit 只能保护容器边界,
不能保证节点整体一定不会 OOM。即使 Pod 是 Guaranteed,也可能因为:
容器超过 memory limit而被 OOMKill。
例如:
当实际使用超过 1Gi 时,仍可能:
OOMKilledGuaranteed 的含义更接近:
request 和 limit 边界一致,资源行为更可预测而不是:
无限内存保证如果配置:
这有助于获得更明确的 CPU 资源边界,但不自动等于 CPU 独占。
通常还需要:
CPU Manager static policy
整数 CPU request
Guaranteed QoS
节点有可分配的独占 CPU查看 kubelet CPU Manager 配置需要在节点上检查 kubelet 配置文件或启动参数。
如果应用对 CPU 抖动极其敏感,还需要结合:
如果 HPA 根据 Pod CPU 利用率扩缩容,而 Pod 中包含:
业务容器
Service Mesh Sidecar那么总 CPU 使用量可能包括 Sidecar 消耗。
例如:
业务容器实际使用:200m
Sidecar 实际使用:100m
业务容器 CPU request:250m
Sidecar CPU request:100mPod 总利用率可能基于:
300m / 350m而不是业务容器单独的:
200m / 250m这可能使 HPA 提前扩容。
生产环境需要确认:
ContainerResource 指标只观察业务容器示例:
这需要确认 Kubernetes 版本和 metrics-server 支持情况。
ContainerResource 指标避免 Sidecar 干扰传统 HPA:
通常按照 Pod 中相关容器的资源汇总进行计算。
如果需要只观察主业务容器,可以考虑:
适合:
但应测试指标链路和升级兼容性,不能只修改 YAML 后直接认为行为正确。
如果集群或工作负载支持原地资源调整,修改资源后 Pod 的 QoS 可能发生变化。
例如从:
修改为:
Pod 可能从:
Guaranteed变为:
Burstable生产环境资源调整时要确认:
较新 Kubernetes 版本开始支持 Pod 级别资源声明:
但具体行为取决于:
生产环境不要仅因为 API Server 接受字段,就认为整个资源链路已经完整支持。应验证:
并确认:
如果生产 Namespace 不允许 BestEffort,可以用 Admission Policy、Kyverno 或 Gatekeeper 强制:
每个业务容器必须配置:
requests.cpu
requests.memory
limits.memory策略目标可以是:
生产 Namespace 禁止 BestEffort
生产 Namespace 必须至少是 Burstable
关键 Namespace 必须使用 Guaranteed但不建议简单地全局禁止所有非 Guaranteed Pod,因为:
应按 Namespace、工作负载类型或标签分级。
QoS 不直接计算成本,但资源声明会影响成本。
例如:
Guaranteed:
request 通常较高且与 limit 相等可能导致:
而:
Burstable:
request 较低,limit 较高可能提高利用率,但会增加:
生产环境应在以下目标之间平衡:
稳定性
利用率
成本
弹性
可预测性不要把某一个 QoS 等级视为所有场景的最优解。
可以建立以下监控维度:
示例思路:
count by (qos_class) (
kube_pod_status_qos_class
)不同 kube-state-metrics 版本的指标名称可能不同,实际应先确认:
curl http://kube-state-metrics:8080/metrics | rg "qos|pod"QoS:Guaranteed
Priority:高
副本:跨节点和可用区
PDB:配置
HPA:谨慎配置QoS:Burstable
Priority:普通
副本:至少 2 个
HPA:根据 request 计算QoS:Burstable
Priority:低或普通
允许突发
设置 activeDeadlineSeconds
设置 backoffLimitQoS:BestEffort 或低资源 Burstable
禁止进入核心生产 Namespace
限制生命周期不要问:
所有 Pod 是否都是 Guaranteed?更应该问:
最终可以这样总结:
QoS 是 Kubernetes 对 Pod 资源保障方式的分类,
不是业务优先级,也不是 SLA。三类 QoS 的生产定位通常是:
Guaranteed:
高可预测性、高资源保障、成本和调度压力较高
成熟的生产方案不是把所有 Pod 强行变成 Guaranteed,而是:
这样才能让 QoS 真正服务于生产稳定性、集群利用率和成本控制。 还有一些更底层但很有用的补充。到这里,QoS 的主体已经完整,下面主要讲实现细节、边界修正和生产治理建议。
Kubernetes 的 QoS Class 挂在 Pod 上:
status:
qosClass: Burstable不存在:
app 容器是 Guaranteed
sidecar 容器是 Burstable这种独立 QoS 分类。
只要 Pod 内任意一个相关容器不满足 Guaranteed 条件,整个 Pod 通常就会降为 Burstable。
例如:
app:
request = limit
sidecar:
request < limit最终:
整个 Pod = Burstable所以生产排查时一定要检查完整的 Pod,而不是只看主业务容器。
Deployment、StatefulSet、DaemonSet 本身没有 QoS Class。
QoS 只属于它们创建出来的 Pod。
例如:
Deployment
├── Pod A:Guaranteed
├── Pod B:Guaranteed
└── Pod C:Burstable如果不同 PodTemplate 或 Admission Webhook 导致资源配置不同,同一个 Deployment 的 Pod 可能出现不同 QoS。
查看:
kubectl get pods -n production \
-o custom-columns='NAME:.metadata.name,QOS:.status.qosClass'生产环境应避免同一工作负载在滚动发布期间出现不可预期的 QoS 混杂。
Linux 内核会使用 OOM 评分决定内存不足时更倾向终止哪些进程。Kubernetes 会根据 QoS 和资源配置调整容器相关的 OOM 行为。
粗略理解:
BestEffort:最容易成为 OOM 目标
Burstable:与实际使用量和 request 相关
Guaranteed:通常更受保护但实际结果仍受以下因素影响:
因此不能仅凭 QoS 预测某个 Pod 一定会最后被杀。
例如:
requests:
Pod 是 Burstable。
如果应用逐步使用到:
1.9Gi虽然没有超过 limit,但它已经明显超过 request。在节点内存压力下,它的风险会增加。
这说明:
request 不只是调度数字,
也是内存压力下的重要参考线。内存 request 设置过小,会产生“调度看起来很轻,运行时实际很重”的问题。
有些人为了让 Pod 变成 Guaranteed,会把 request 和 limit 设置成相等,但数值明显高于实际合理需求:
可能造成:
正确做法是:
先根据实际负载确定合理 request,
再决定是否让 request 等于 limit。QoS 是资源设计的结果,不应该成为资源配置的唯一目标。
假设两个服务实际都使用 500m CPU:
服务 A:
requests:
cpu: "250m"HPA 看到约:
200%服务 B:
requests:
cpu: "2"HPA 看到约:
25%即使服务 B 实际使用量更高,它反而可能不扩容。
所以:
为了提高 QoS 级别而盲目提高 request,
可能让 HPA 失去敏感性。生产中应同时评估:
Pod 是 Guaranteed,并不意味着 Service 会优先把流量发送给它。
Service 主要依据:
QoS 不会自动影响:
Service 负载均衡权重
Ingress 路由
请求优先级
客户端连接分配如果需要业务流量优先级,需要使用:
关注:
资源压力和资源配置关注:
主动中断时允许同时减少多少 Pod一个 Pod 可以是:
Guaranteed + 有 PDB也可以是:
Burstable + 有 PDBPDB 不会阻止:
QoS 也不能代替 PDB。
oom_score_adj 不应作为业务控制手段可以在容器中查看:
cat /proc/1/oom_score_adj但不建议业务依赖这个值来实现高可用或容灾逻辑。
原因:
业务保护应使用 Kubernetes 正式机制和应用自身容灾设计。
资源变更不只是修改一个数字。
可能导致:
Pod 无法调度
HPA 利用率下降
ResourceQuota 快速消耗
Cluster Autoscaler 扩容可能导致:
调度成功但节点超卖增加
节点压力风险增加
Pod 更容易被驱逐
HPA 利用率升高可能缓解:
OOMKill但也可能导致:
单个 Pod 占用过多内存
节点级 OOM
集群超卖加重可能造成:
应用频繁 OOM
重启次数增加
服务抖动资源变更必须同时观察:
Pod 状态
节点状态
HPA
ResourceQuota
应用延迟
OOM 和驱逐例如:
| 工作负载 | QoS | Priority | 说明 |
|---|---|---|---|
| 核心支付 | Guaranteed | 高 | 资源需求稳定 |
| 普通 API | Burstable | 普通 | 允许合理突发 |
| 批处理 | Burstable | 低 | 可延迟、可重试 |
| 临时调试 | BestEffort | 默认 | 可随时删除 |
| 节点关键 Agent | 视组件设计 | 高或系统级 | 需要谨慎配置 |
对应 Namespace 可以划分为:
core-prod
service-prod
batch-prod
debug每个 Namespace 配置不同的:
例如生产环境禁止 BestEffort,可以制定规则:
production Namespace 中:
- 每个容器必须有 memory request
- 每个容器必须有 CPU request
- 每个容器必须有 memory limit
- 禁止资源完全为空如果核心 Namespace 要求 Guaranteed,可以进一步规定:
CPU request 必须等于 CPU limit
Memory request 必须等于 memory limit但需要为以下对象单独设计例外:
策略不能只按“所有 Pod 一刀切”,否则容易影响合法场景。
同一个服务在发布前后 QoS 发生变化,是生产中常见但容易忽略的问题。
例如:
旧版本:Guaranteed
新版本:Burstable原因可能是:
发布后建议检查:
还可以在发布系统中加入校验:
核心服务发布后 QoS 必须保持 Guaranteed不同工作负载可以使用不同节点池:
system pool
core service pool
general service pool
batch pool
GPU pool
memory-optimized pool通过:
nodeSelector:
workload: core以及:
让不同 QoS 和业务等级的 Pod 进入不同资源池。
例如:
核心 Guaranteed 服务 -> 专用节点
普通 Burstable 服务 -> 通用节点
批处理 -> 可抢占或低成本节点
GPU -> GPU 节点这样比单纯依赖 QoS 更容易实现隔离和容量规划。
可以采用以下决策逻辑:
Kubernetes QoS 的完整定位是:
QoS 是 Pod 资源配置的分类机制,
用于帮助 Kubernetes 和运维系统理解 Pod 的资源保障程度。它不是:
业务 SLA
网络优先级
绝对调度优先级
绝对高可用保证
绝对不被驱逐的承诺三种 QoS 的生产含义可以归纳为:
Guaranteed:
边界清晰、可预测性高、资源成本高
最终推荐的生产组合是:
这样,QoS 才能真正成为生产资源治理的一部分,而不是仅仅查看 Pod 上的一个 qosClass 字段。
有,但已经进入“边界与实践收尾”阶段,不再是新的核心概念。最后补充几个容易遗漏的点。
QoS 不是由用户直接设置的字段,不能写:
qosClass: Guaranteed它由 Kubernetes 根据 Pod 最终资源配置自动计算:
kubectl get pod <pod-name> -o jsonpath='{.status.qosClass}'最终配置可能受到以下因素影响:
因此,应检查服务端最终对象:
kubectl create
即使设置了 Guaranteed,也仍然需要:
QoS 只能改善资源压力下的行为,不能解决:
生产容量规划至少要同时看:
例如,不能只因为 Pod 都是 Guaranteed,就认为集群容量足够。
可以在 CI/CD 或发布后检查:
核心服务可以设置发布约束:
旧版本:Guaranteed
新版本:必须仍为 Guaranteed普通服务则可以检查:
不能变成 BestEffort
request 不能低于基线
memory limit 不能被意外删除仅查看 QoS 字段不够,建议在测试环境验证:
重点观察:
可以把完整资源治理分成几层:
最终结论:
Guaranteed 适合资源稳定、重要且需要高可预测性的服务;
Burstable 是大多数生产业务的平衡选择;
BestEffort 适合临时、低优先级、可丢失的工作负载。核心原则不是“所有 Pod 都变成 Guaranteed”,而是:
根据业务重要性、资源波动、成本目标和故障容忍度选择 QoS,
再用实际监控数据持续校准 requests 和 limits。到这里,Kubernetes QoS 从分类规则、资源行为、驱逐机制、HPA、VPA、Priority、Sidecar、Init Container、节点压力、生产治理和故障演练等方面已经基本完整。
apiVersion: v1
kind: Pod
metadata:
name: guaranteed-pod
spec:
containers:
- name: app
image: nginx:1.27
resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "1"
memory: "1Gi"containers:
- name: app
image: example/app:v1
resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "1"
memory: "1Gi"
- name: sidecar
image: example/sidecar:v1
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "100m"
memory: "128Mi"resources:
requests:
cpu: "2"
limits:
cpu: "2"resources:
requests:
cpu: "500m"
limits:
cpu: "500m"apiVersion: v1
kind: Pod
metadata:
name: burstable-pod
spec:
containers:
- name: app
image: nginx:1.27
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"apiVersion: v1
kind: Pod
metadata:
name: besteffort-pod
spec:
containers:
- name: app
image: nginx:1.27kubectl get pod <pod-name> -n <namespace> \
-o jsonpath='{.status.qosClass}{"\n"}'spec:
containers:
- resources:
requests:
limits:requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "1"
memory: "1Gi"requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"resources:
requests:
ephemeral-storage: "512Mi"
limits:
ephemeral-storage: "2Gi"apiVersion: v1
kind: Pod
metadata:
name: critical-api
spec:
priorityClassName: production-critical
containers:
- name: api
image: example/api:v1
resources:
requests:
cpu: "2"
memory: "4Gi"
limits:
cpu: "2"
memory: "4Gi"resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "1"
memory: "1Gi"resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "4"
memory: "8Gi"resources:
requests:
cpu: "2"
memory: "8Gi"
limits:
cpu: "2"
memory: "8Gi"apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-api
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: payment-api
template:
metadata:
labels:
app: payment-api
spec:
containers:
- name: payment-api
image: registry.example.com/payment-api:v2.1.0
resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "1"
memory: "1Gi"apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: registry.example.com/web:v1.5.0
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"apiVersion: v1
kind: Pod
metadata:
name: debug-shell
namespace: test
spec:
restartPolicy: Never
containers:
- name: shell
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]apiVersion: v1
kind: Pod
metadata:
name: app-with-proxy
namespace: production
spec:
containers:
- name: app
image: example/app:v1
resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "1"
memory: "1Gi"
- name: proxy
image: example/proxy:v1
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "100m"
memory: "128Mi"resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "200m"
memory: "128Mi"apiVersion: batch/v1
kind: Job
metadata:
name: report-generation
namespace: batch
spec:
backoffLimit: 2
template:
spec:
restartPolicy: Never
containers:
- name: report
image: example/report:v1
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "4"
memory: "8Gi"apiVersion: v1
kind: Pod
metadata:
name: inference
namespace: ai
spec:
containers:
- name: inference
image: example/inference:v1
resources:
requests:
cpu: "2"
memory: "8Gi"
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: "16Gi"
nvidia.com/gpu: 1apiVersion: v1
kind: LimitRange
metadata:
name: default-resources
namespace: production
spec:
limits:
- type: Container
defaultRequest:
cpu: "200m"
memory: "256Mi"
default:
cpu: "1"
memory: "1Gi"resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "1Gi"defaultRequest:
cpu: "1"
memory: "1Gi"
default:
cpu: "1"
memory: "1Gi"apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "100"
requests.memory: "200Gi"
limits.cpu: "200"
limits.memory: "400Gi"
pods: "200"spec:
initContainers:
- name: init
image: busybox:1.36
resources:
requests:
cpu: "2"
memory: "2Gi"
limits:
cpu: "2"
memory: "2Gi"
containers:
- name: app
image: nginx:1.27
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "500m"
memory: "512Mi"resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"kubectl get pod <pod-name> -n <namespace> \
-o jsonpath='{.status.qosClass}{"\n"}'kubectl top pod <pod-name> -n <namespace> --containers
kubectl top node
kubectl describe node <node-name>kubectl describe pod <pod-name> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestampBestEffort Pod 数量
Burstable Pod 数量
Guaranteed Pod 数量
CPU request/limit
内存 request/limit
OOMKill
驱逐
CPU throttling
节点压力resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "1"
memory: "1Gi"resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "1Gi"resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "4"
memory: "8Gi"核心服务:
Guaranteed 或高质量 Burstable
普通在线服务:
Burstable
批处理:
Burstable + 合理 Priority
临时调试:
BestEffortLimitRange
ResourceQuota
PriorityClass
PDB
HPA/VPA
Admission Policy
节点资源预留
监控和告警resources:
requests:
cpu: "1"
memory: "1Gi"
ephemeral-storage: "1Gi"
limits:
cpu: "1"
memory: "1Gi"
ephemeral-storage: "2Gi"requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "1"
memory: "1Gi"resources:
requests:
cpu: "500m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "1"
memory: "1Gi"resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "200m"
memory: "128Mi"dmesg
journalctl -u kubelet
journalctl -u containerd
kubectl describe node <node-name>resources:
requests:
memory: "1Gi"
limits:
memory: "1Gi"resources:
requests:
cpu: "1"
limits:
cpu: "1"metrics:
- type: ContainerResource
containerResource:
name: cpu
container: app
target:
type: Utilization
averageUtilization: 70metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70metrics:
- type: ContainerResource
containerResource:
name: cpu
container: app
target:
type: Utilization
averageUtilization: 70requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "1"
memory: "1Gi"requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"spec:
resources:
requests:
cpu: "2"
memory: "2Gi"
limits:
cpu: "2"
memory: "2Gi"kubectl explain pod.spec.resources
kubectl get pod <pod-name> -o yaml
kubectl describe pod <pod-name>各 Namespace 的 QoS 分布
BestEffort Pod 数量
Guaranteed Pod 数量
Burstable Pod 数量
OOMKill 次数
Evicted Pod 数量
CPU throttling
MemoryPressure
DiskPressure
PIDPressure
Pod 重启次数
Pending Pod 数量
ResourceQuota 使用率resources:
requests:
cpu: "2"
memory: "4Gi"
limits:
cpu: "2"
memory: "4Gi"resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "4"
memory: "8Gi"核心服务是否有明确资源边界?
普通服务是否有合理 request?
批处理是否允许合理突发?
BestEffort 是否只存在于可接受的场景?
Sidecar 是否被纳入资源和 QoS 评估?
HPA 是否使用了正确的 request?
节点是否有足够预留?
OOM 和驱逐是否可观测?
高优先级是否受到权限限制?按业务重要性和资源特征分级
显式配置 requests/limits
使用 LimitRange 兜底
使用 ResourceQuota 控制总量
用 PriorityClass 表达调度优先级
用 HPA/VPA 调整资源或副本
监控 OOM、驱逐和 throttling
用 Admission Policy 防止不合规配置requests:
cpu: "8"
memory: "16Gi"
limits:
cpu: "8"
memory: "16Gi"tolerations:
- key: workload
operator: Equal
value: core
effect: NoSchedule是否是核心、延迟敏感、资源稳定的服务?
是 -> 评估 Guaranteed + 专用节点
是否是普通在线服务?
是 -> 通常使用 Burstable
是否是可重试、可延迟的批处理?
是 -> Burstable + 较低 Priority
是否是临时、可丢失任务?
是 -> 可以使用 BestEffort
是否有 Sidecar?
是 -> 重新计算整个 Pod 的 QoS 和资源
是否有 HPA?
是 -> 重点校准 CPU/内存 request
是否有节点压力风险?
是 -> 检查 request、limit、超卖率和驱逐合理 requests/limits
+ LimitRange
+ ResourceQuota
+ PriorityClass
+ PDB
+ HPA/VPA
+ 节点池隔离
+ Admission Policy
+ OOM/驱逐/throttling 监控
+ 持续资源校准多副本
跨节点分布
跨可用区分布
Service
PDB
持久化存储
数据复制
备份恢复
应用重试CPU request 总量
内存 request 总量
CPU limit 总量
内存 limit 总量
实际使用量
节点可分配资源
系统预留资源
DaemonSet 资源
发布期间 maxSurge
HPA 最大副本数
批处理并发量节点内存压力
容器超过 memory limit
CPU limit throttling
Pod eviction
Deployment 滚动发布
HPA 扩容
节点 drain
Sidecar 异常
Init Container 失败QoS:
Pod 的资源保障分类
requests/limits:
单个容器的资源需求和上限
LimitRange:
单个对象的默认值和边界
ResourceQuota:
Namespace 的资源总量
PriorityClass:
调度和抢占优先级
PDB:
主动中断保护
HPA/VPA:
动态扩缩和资源建议
节点池:
硬件和故障域隔离
监控:
验证资源策略是否合理