中文内容
Kubernetes v1.36:通过 Memory QoS 实现分层内存保护
我们代表 SIG Node,很高兴宣布 Kubernetes v1.36 中 Memory QoS 功能(alpha)的更新。Memory QoS 使用 cgroup v2 内存控制器,为内核提供更好的指引,以决定如何处理容器内存。该功能最早在 v1.22 中引入,并在 v1.27 中更新。在 Kubernetes v1.36 中,我们引入了:可选的内存预留、按 QoS 类分层保护、可观测性指标,以及针对 memory.high 的内核版本警告。
v1.36 的新增内容
使用 memoryReservationPolicy 的可选内存预留
v1.36 将限流与预留分离。启用功能门控会开启 memory.high 限流(kubelet 根据 memoryThrottlingFactor 设置 memory.high,默认值为 0.9),但内存预留现在由一个单独的 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 获得软保护。对于同样请求 512 MiB 的 Burstable Pod:
$ cat /sys/fs/cgroup/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod8b3c7d2e_4f5a_6b7c_9d1e_3f4a5b6c7d8e.slice/memory.low
536870912
在正常压力下,内核会避免回收这部分内存;但如果替代结果是系统级 OOM,则可能会回收它。
BestEffort Pod 既不会获得 memory.min,也不会获得 memory.low。其内存仍然可以被完全回收。
与 v1.27 行为的比较
在早期版本中,启用 MemoryQoS 功能门控会立即为每个带有内存请求的容器设置 memory.min。memory.min 是硬预留,无论内存压力如何,内核都不会回收。
考虑一个拥有 8 GiB RAM 的节点,其中 Burstable Pod 的请求总量为 7 GiB。在早期版本中,这 7 GiB 会作为 memory.min 被锁定,留给内核、系统守护进程或 BestEffort 工作负载的余量很少,并增加 OOM kill 的风险。
在 v1.36 的分层预留中,这些 Burstable 请求会映射到 memory.low,而不是 memory.min。在正常压力下,内核仍会保护这部分内存;但在极端压力下,它可以回收其中一部分,以避免系统级 OOM。只有 Guaranteed Pod 使用 memory.min,从而降低硬预留量。
借助 v1.36 中的 memoryReservationPolicy,你可以先启用限流,观察工作负载行为,并在节点有足够余量时选择启用预留。
可观测性指标
kubelet 的 /metrics 端点暴露了两个 alpha 稳定性指标:
MetricDescriptionkubelet_memory_qos_node_memory_min_bytesTotal memory.min across Guaranteed Podskubelet_memory_qos_node_memory_low_bytesTotal memory.low across Burstable Pods这些指标对容量规划很有用。如果 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 限流可能触发内核 livelock 问题。该 bug 已在内核 5.9 中修复。在 v1.36 中,当功能门控启用时,kubelet 会在启动时检查内核版本,并在版本低于 5.9 时记录一条警告。该功能会继续工作——这只是信息提示,而不是硬性阻止。
Kubernetes 如何将 Memory QoS 映射到 cgroup v2
Memory 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 Classmemory.minmemory.lowmemory.highmemory.maxGuaranteedSet torequests.memory(hard protection)Not setNot set
(requests == limits, so throttling is not useful)Set to
limits.memoryBurstableNot setSet to requests.memory(soft protection)Calculated based on
formula with throttling factorSet to
limits.memory(if specified)BestEffortNot setNot setCalculated based on
node allocatable memoryNot set
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,而容器级 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+)
配置
要启用带分层保护的 Memory 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 服务质量类别
- 管理容器资源
- Kubernetes cgroups v2 支持
- Linux 内核 cgroups v2 文档
参与其中
该功能由 SIG Node 推动。如果你有兴趣贡献或提供反馈,可以通过 Slack(#sig-node)、邮件列表或定期 SIG Node 会议找到我们。请在 kubernetes/kubernetes 提交 bug,并在 kubernetes/enhancements 提交增强提案。
- ← 上一篇
- 下一篇 →