本文发布已超过一年。较早的文章可能包含过时的内容。请核实页面信息自发布以来是否已不再准确。
内存资源的质量服务(Quality-of-Service)
Kubernetes v1.22 版本于 2021 年 8 月发布,引入了一个新的 Alpha 特性,改进了 Linux 节点实现内存资源请求和限制的方式。
在之前的版本中,Kubernetes 不支持内存质量保证。例如,如果您按如下方式设置容器资源:
apiVersion: v1
kind: Pod
metadata:
name: example
spec:
containers:
- name: nginx
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "64Mi"
cpu: "500m"
spec.containers[].resources.requests
(例如 cpu, memory) 是为调度设计的。当你创建一个 Pod 时,Kubernetes 调度器会为其选择一个节点运行。每个节点对于每种资源类型都有最大容量:它可以为 Pods 提供的 CPU 和内存量。调度器确保,对于每种资源类型,已调度容器的资源请求总和小于节点的容量。
spec.containers[].resources.limits
在 kubelet 启动容器时传递给容器运行时。CPU 被认为是“可压缩”资源。如果你的应用开始达到 CPU 限制,Kubernetes 会开始限制你的容器,可能导致应用性能下降。然而,它不会被终止。这就是“可压缩”的含义。
在 cgroup v1 中以及此特性之前,容器运行时从未考虑且实际上忽略了 spec.containers[].resources.requests["memory"]。这与 CPU 不同,对于 CPU,容器运行时会同时考虑请求和限制。此外,在 cgroup v1 中内存实际上无法压缩。由于无法限制内存使用,如果容器超出其内存限制,它将被内核以 OOM(内存不足)杀死终止。
幸运的是,cgroup v2 带来了新的设计和实现,可以在内存上实现全面保护。新特性依赖于 cgroup v2,目前大多数 Linux 操作系统版本已经提供了该功能。通过此实验性特性,针对 Pods 和容器的服务质量(QoS)不仅涵盖 CPU 时间,也扩展到了内存。
工作原理是什么?
内存 QoS 使用 cgroup v2 的内存控制器来保障 Kubernetes 中的内存资源。Pod 中容器的内存请求和限制用于设置内存控制器提供的特定接口 memory.min
和 memory.high
。当 memory.min
设置为内存请求时,内存资源被保留,并且永远不会被内核回收;这就是内存 QoS 如何确保 Kubernetes Pods 可用内存的方式。如果在容器中设置了内存限制,这意味着系统需要限制容器的内存使用量,内存 QoS 使用 memory.high
来限制接近其内存限制的工作负载,确保系统不会因瞬时内存分配而过载。
下表详细介绍了这两个参数的具体功能以及它们与 Kubernetes 容器资源的对应关系。
文件 | 描述 |
---|---|
memory.min | memory.min 指定 cgroup 必须始终保留的最小内存量,即永远不会被系统回收的内存。如果 cgroup 的内存使用达到此下限且无法增加,则会调用系统 OOM killer。我们将其映射到容器的内存请求 |
memory.high | memory.high 是内存使用限制阈值。这是控制 cgroup 内存使用的主要机制。如果 cgroup 的内存使用超出此处指定的高位边界,则 cgroup 的进程将被限制,并承受沉重的回收压力。默认值为 max,表示没有限制。我们使用一个公式计算 memory.high ,该公式取决于容器的内存限制或节点可分配内存(如果容器的内存限制为空)以及一个限制因子。有关该公式的更多详细信息,请参阅 KEP。 |
提出容器内存请求后,kubelet 会在容器创建期间通过 CRI 中的 Unified
字段将 memory.min
传递给后端 CRI 运行时(可能是 containerd、cri-o)。容器级别 cgroup 中的 memory.min
将设置为
i:Pod 中的第 i 个容器
由于 memory.min
接口要求祖先 cgroup 目录都已设置,因此需要正确设置 Pod 和节点 cgroup 目录。
Pod 级别 cgroup 中的 memory.min
i:Pod 中的第 i 个容器
节点级别 cgroup 中的 memory.min
i:节点中的第 i 个 Pod,j:Pod 中的第 j 个容器
Kubelet 将使用 runc libcontainer 库直接管理 Pod 级别和节点级别 cgroups 的 cgroup 层次结构,而容器 cgroup 限制由容器运行时管理。
对于内存限制,除了限制内存使用的原始方式外,内存 QoS 还增加了限制内存分配的附加特性。引入了一个限制因子作为乘数(默认为 0.8)。如果内存限制乘以该因子的结果大于内存请求,kubelet 将把 memory.high
设置为该值,并通过 CRI 使用 Unified
。如果容器未指定内存限制,kubelet 将转而使用节点可分配内存。容器级别 cgroup 中的 memory.high
设置为
i:Pod 中的第 i 个容器
这有助于在 Pod 内存使用量增加时提高稳定性,确保在接近内存限制时限制内存使用。
如何使用它?
以下是在 Linux 节点上启用内存 QoS 的先决条件,其中一些与 Kubernetes 对 cgroup v2 的支持有关。
- Kubernetes v1.22 及更高版本
- runc v1.0.0-rc93 及更高版本;containerd 1.4 及更高版本;cri-o 1.20 及更高版本
- Linux 内核最低版本:4.15,推荐版本:5.2+
- 启用 cgroup v2 的 Linux 镜像或手动启用 cgroup v2 unified_cgroup_hierarchy
runc 和 crun 等 OCI 运行时已支持 cgroups v2 Unified
,并且 Kubernetes CRI 也已进行了相应的更改以支持传递 Unified
。然而,还需要 CRI 运行时支持。Alpha 阶段的内存 QoS 特性旨在支持 containerd 和 cri-o。相关的 PR Feature: containerd-cri support LinuxContainerResources.Unified #5627 已合并,并将随 containerd 1.6 版本发布。CRI-O 的 implement kube alpha features for 1.22 #5207 仍在进行中 (WIP)。
满足这些先决条件后,你可以启用内存 QoS 特性门(参见通过配置文件设置 kubelet 参数)。
如何了解更多?
你可以通过以下方式了解更多详情
如何参与?
你可以通过多种方式联系 SIG Node
你也可以直接联系我
- GitHub / Slack:@xiaoxubeii
- 邮箱:xiaoxubeii@gmail.com