协会地址:上海市长宁区古北路620号图书馆楼309-313室
Kubernetes v1.36:带内存 QoS 的分层内存保护
原文链接:https://kubernetes.io/blog/2026/04/29/kubernetes-v1-36-memory-qos-tiered-protection/
代表 SIG 节点(Node),我们很高兴地宣布 Kubernetes v1.36 中 Memory QoS 功能(alpha)的更新。Memory QoS 利用 cgroup v2 内存控制器,让内核更好地指导如何处理容器内存。该功能最初在 v1.22 中引入,并在 v1.27 中更新。在 Kubernetes v1.36 中,我们引入了:可选内存预留(opt-in memory reservation)、按 QoS 类(QoS class)的分级保护、可观测性指标(observability metrics),以及针对 memory.high 的内核版本警告。
v1.36 中的新功能
通过 memoryReservationPolicy 实现可选内存预留
v1.36 将限制(throttling)与预留(reservation)分离开来。启用特性门控(feature gate)会开启 memory.high 限制(kubelet 根据 memoryThrottlingFactor(默认值为 0.9)设置 memory.high),但现在内存预留由一个独立的 kubelet 配置字段控制:
- None(默认值):不写入
memory.min或memory.low。通过memory.high进行的限制仍有效。 - TieredReservation:kubelet 根据 Pod 的 QoS 类 写入分级内存保护:
Guaranteed Pod 通过 memory.min 获得硬保护。例如,一个请求 512 MiB 内存的 Guaranteed Pod 会导致:
$ cat /sys/fs/cgroup/kubepods.slice/kubepods-pod6a4f2e3b_1c9d_4a5e_8f7b_2d3e4f5a6b7c.slice/memory.min
536870912
内核在任何情况下都不会回收此内存。如果它无法履行保证,则会调用其他进程上的 OOM killer(内存溢出杀手)来释放页面。
Burstable(可突发)Pod 通过 memory.low 获得软保护。对于 Burstable Pod 上同样的 512 MiB 请求:
$ cat /sys/fs/cgroup/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod8b3c7d2e_4f5a_6b7c_9d1e_3f4a5b6c7d8e.slice/memory.low
536870912
内核在正常压力下会避免回收这部分内存,但若不作回收将导致系统范围内 OOM(Out Of Memory,内存耗尽)时,则允许回收。
BestEffort Pod 既无 memory.min 也无 memory.low。其内存完全可回收。
与 v1.27 行为的对比
在早期版本中,启用 MemoryQoS 特性门控后,会立即为每个带有内存请求(memory request)的容器设置 memory.min。memory.min 是一种硬性预留(hard reservation),内核在任何内存压力下都不会回收。
假设有一个节点拥有 8 GiB 内存,其中 Burstable Pod 请求总量为 7 GiB。在早期版本中,这 7 GiB 会被锁定为 memory.min,留给内核、系统守护进程或 BestEffort 工作负载的余地很小,增加了 OOM 杀死的风险。
在 v1.36 的分层预留(tiered reservation)中,这些 Burstable 的请求映射到 memory.low 而非 memory.min。正常压力下,内核仍保护该内存,但在极端压力下可以回收其中一部分以避免系统范围 OOM。只有 Guaranteed Pod 使用 memory.min,这使得硬性预留更低。
通过 v1.36 的 memoryReservationPolicy,你可以先启用限流,观察工作负载表现,并在节点有足够余量时选择启用预留。
可观测性指标
在 kubelet 的 /metrics 端点暴露了两个 alpha 稳定性指标:
| 指标 | 描述 |
|---|---|
kubelet_memory_qos_node_memory_min_bytes | 所有 Guaranteed Pod 的 memory.min 总和 |
kubelet_memory_qos_node_memory_low_bytes | 所有 Burstable Pod 的 memory.low 总和 |
这些指标有助于容量规划。如果 kubelet_memory_qos_node_memory_min_bytes 逐渐接近节点的物理内存,说明硬性预留已趋紧张。
$ curl -sk https://localhost:10250/metrics | grep memory_qos
# HELP kubelet_memory_qos_node_memory_min_bytes [ALPHA] Total memory.min in bytes for Guaranteed pods
kubelet_memory_qos_node_memory_min_bytes 5.36870912e+08
# HELP kubelet_memory_qos_node_memory_low_bytes [ALPHA] Total memory.low in bytes for Burstable pods
kubelet_memory_qos_node_memory_low_bytes 2.147483648e+09
内核版本检查
在内核版本早于 5.9 的系统上,memory.high 节流可能触发内核活锁(kernel livelock)问题。该问题已在内核 5.9 中修复。在 v1.36 中,当该特性门控启用时,kubelet 会在启动时检查内核版本,若版本低于 5.9 则记录一条警告。此功能仍可正常工作——这仅作为信息提示,并非硬性阻断。
Kubernetes 如何将内存 QoS 映射到 cgroup v2
内存 QoS 使用了四个 cgroup v2 内存控制器接口:
- memory.max:硬内存限制——与先前版本保持一致
- memory.min:硬内存保护——配合
TieredReservation时,仅对保证级(Guaranteed)Pod 设置 - memory.low:软内存保护——配合
TieredReservation时,对可突发级(Burstable)Pod 设置 - memory.high:内存节流阈值——与先前版本保持一致
下表显示了当配置 memoryReservationPolicy: TieredReservation 时,Kubernetes 容器资源如何映射到 cgroup v2 接口。当使用默认的 memoryReservationPolicy: None 时,不会设置任何 memory.min 或 memory.low 值。
| QoS 类别 | memory.min | memory.low | memory.high | memory.max |
|---|---|---|---|---|
| 保证级(Guaranteed) | 设置为 requests.memory(硬保护) | 未设置 | 未设置(requests == limits,节流无意义) | 设置为 limits.memory |
| 可突发级(Burstable) | 未设置 | 设置为 requests.memory(软保护) | 基于节流因子公式计算得出 | 设置为 limits.memory(若指定) |
| 尽力而为级(BestEffort) | 未设置 | 未设置 | 基于节点可分配内存计算得出 | 未设置 |
cgroup 层级结构
cgroup v2 要求父 cgroup 的内存保护值至少等于其所有子 cgroup 保护值之和。kubelet 通过以下方式维护这一要求:在 kubepods 根 cgroup 上将 memory.min 设置为所有保证级(Guaranteed)和可突发级(Burstable)Pod 内存请求之和,并在可突发级(Burstable)QoS cgroup 上将 memory.low 设置为所有可突发级(Burstable)Pod 内存请求之和。这样内核就可以正确地强制实施每个容器和每个 Pod 的保护值。
kubelet 使用 runc 的 libcontainer 库直接管理 Pod 级别和 QoS 类别的 cgroup,而容器级别(container-level)的 cgroup 则由容器运行时(containerd 或 CRI-O)管理。
如何使用?
前提条件
- Kubernetes v1.36 或更高版本
- 支持 cgroup v2 的 Linux 系统。建议内核版本为 5.9 或更高——更早的内核仍可工作,但可能遇到活锁(livelock)问题。可以通过运行
mount | grep cgroup2来验证 cgroup v2 是否已激活。 - 支持 cgroup v2 的容器运行时(containerd 1.6+、CRI-O 1.22+)
配置
启用具有分层保护的内存 QoS:
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
featureGates:
MemoryQoS: true
memoryReservationPolicy: TieredReservation # Options: None (default), TieredReservation
memoryThrottlingFactor: 0.9 # Optional: default is 0.9
如果你想要 memory.high 节流但没有内存保护,请省略 memoryReservationPolicy 或将其设置为 None:
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
featureGates:
MemoryQoS: true
memoryReservationPolicy: None # This is the default
如何了解更多?
- KEP-2570:内存服务质量(Memory QoS)
- Pod 服务质量类(Quality of Service Classes)
- 管理容器资源
- Kubernetes cgroups v2 支持
- Linux 内核 cgroups v2 文档
参与贡献
此功能由 SIG Node 推动。如果您有兴趣贡献或提供反馈,可以通过 Slack(#sig-node 频道)、邮件列表 或在定期的 SIG Node 会议 上找到我们。请在 kubernetes/kubernetes 提交 bug,并在 kubernetes/enhancements 提交增强提案。







