bigywater.tech
Kubernetes · 36

QoS 等级:Guaranteed、Burstable、BestEffort 的划分

QoS 等级听起来是个标签,其实它决定了容器放在 cgroup 的哪一层、被 OOM 杀手选中的顺序和节点压力时被驱逐的先后。这篇用七种 requests/limits 组合验证分级规则,再直接去节点里读 cgroup 和 oom_score_adj,最后试着改变一个运行中 Pod 的等级。

-997 / 996 / 1000
Guaranteed、Burstable(32Mi 内存请求)、BestEffort Pod 里进程的 oom_score_adj
7 → 3
七种 requests/limits 组合落到的三个 QoS 等级
may not change
在线调整资源会改变 QoS 等级时被拒绝的原因

谁是哪一级

实测 · 本机执行输出
  guar       Guaranteed  requests = limits(cpu 和 memory,每个容器)
  guar-lim   Guaranteed  只写了 limits(requests 自动等于 limits)
  burst      Burstable   requests 小于 limits
  burst-req  Burstable   只写了 requests
  burst-mem  Burstable   memory 满足、cpu 只有 requests
  burst-two  Burstable   两个容器,一个满足一个没写
  best       BestEffort  什么都没写

规则看的是 Pod 里所有容器:每个容器的 cpu 和 memory 都有 requests = limits 才是 Guaranteed(只写 limits 也行,requests 自动补成同样的值);不满足但至少有一个 requests 或 limits 就是 Burstable——包括“memory 满足、cpu 只有 requests”和“两个容器一个满足一个没写”这类看起来差一点点的情形;什么都没写才是 BestEffort。

在 cgroup 里的位置

实测 · 本机执行输出
  guar   → kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-pod<uid>.slice
  burst  → kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-burstable.slice/kubelet-kubepods-burstable-pod<uid>.slice
  best   → kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-pod<uid>.slice

kind 节点是 cgroup v2、systemd 驱动。Guaranteed 的 Pod 直接挂在 kubelet-kubepods.slice 下,Burstable 与 BestEffort 各多一层 kubelet-kubepods-burstable.slice 和 kubelet-kubepods-besteffort.slice——内核可以在三类之间整体分配和回收。

内核里的参数

实测 · 本机执行输出
  节点内存容量 7934 MiB(影响 Burstable 的 oom_score_adj 计算)
  guar       Guaranteed  cpu.weight=29   cpu.max=20000 100000   memory.max=67108864    oom_score_adj=-997(按规则应为 -997)
  burst      Burstable   cpu.weight=17   cpu.max=20000 100000   memory.max=67108864    oom_score_adj=996(按规则应为 996)
  burst-req  Burstable   cpu.weight=17   cpu.max=max 100000     memory.max=max         oom_score_adj=999(按规则应为 999)
  best       BestEffort  cpu.weight=1    cpu.max=max 100000     memory.max=max         oom_score_adj=1000(按规则应为 1000)

Guaranteed 的容器:cpu.weight=29、cpu.max=20000 100000(200m)、memory.max=67108864(64Mi),进程 oom_score_adj=-997,几乎不会被 OOM 杀手选中。Burstable 的 oom_score_adj 是 1000 − 1000 × 内存 requests ÷ 节点内存:32Mi 请求得 996,没写内存请求得 999;cpu.max=max、memory.max=max 表示没有 limit。BestEffort 是 1000,cpu.weight=1,最先被杀。同样是 Burstable,内存请求越大越晚被杀。

等级不可变

实测 · 本机执行输出
  Guaranteed 的 guar 只把 cpu limit 改成 400m(requests 仍是 200m,会变成 Burstable):退出码 1;The Pod "guar" is invalid: spec: Invalid value: "Guaranteed": Pod QOS Class may not change as a result of resizing
  requests 与 limits 一起改成 400m(仍是 Guaranteed):退出码 0;pod/guar patched;spec 里 cpu=400m;qosClass=Guaranteed;容器 cpu.max=40000 100000
  BestEffort 的 best 想加一个 requests(会变成 Burstable):退出码 1;The Pod "best" is invalid: spec: Invalid value: "BestEffort": Pod QOS Class may not change as a result of resizing

QoS 在创建时算好,之后只能不变:把 Guaranteed Pod 的 cpu limit 单独改成 400m(requests 仍是 200m,会变成 Burstable)被拒绝,Pod QOS Class may not change as a result of resizing;requests 和 limits 一起改成 400m 则成功,容器的 cpu.max 变成 40000 100000;给 BestEffort 的 Pod 加 requests 同样被拒绝。想换等级只能重建 Pod。

分步演示

QoS 等级
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0,节点是 cgroup v2 + systemd 驱动,kubelet cgroupRoot=/kubelet,节点内存容量 7934 MiB);cgroup 参数用 docker exec 进节点读 /sys/fs/cgroup/kubelet.slice/…,oom_score_adj 读容器 cgroup.procs 里第一个进程的 /proc//oom_score_adj;Burstable 的预期值按公式 1000 − 1000×内存请求÷节点容量(下限 2、上限 999)计算,与实测一致;在线调整用 kubectl patch --subresource=resize;每种情形各一次
    • 没有验证:使用 CPU Manager static 策略时 Guaranteed Pod 的独占核;Memory QoS(cgroup v2 的 memory.min/high)特性;init 容器与 Pod overhead 对 QoS 的影响;hugepages 等扩展资源;节点上 system-reserved/kube-reserved 对 cgroup 层级的影响;cgroup v1 的差别
    京ICP备2026067502号-1京公网安备11010502063487号