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