本文已超过一年。较旧的文章可能包含过时的内容。检查页面中的信息自发布以来是否已不正确。
内存资源的质量服务
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、内存)是为调度而设计的。当您创建一个 Pod 时,Kubernetes 调度器会选择一个节点来运行 Pod。每个节点都具有每种资源类型的最大容量:它可以为 Pod 提供的 CPU 和内存量。调度器确保对于每种资源类型,已调度的容器的资源请求总和小于节点的容量。
当 kubelet 启动容器时,spec.containers[].resources.limits
会传递给容器运行时。CPU 被认为是“可压缩”的资源。如果您的应用程序开始达到 CPU 限制,Kubernetes 将开始限制您的容器,从而可能导致您的应用程序性能下降。但是,它不会被终止。这就是“可压缩”的含义。
在 cgroup v1 中,并且在此功能之前,容器运行时从未考虑过并有效地忽略了 spec.containers[].resources.requests["memory"]。这与 CPU 不同,在 CPU 中,容器运行时会同时考虑请求和限制。此外,在 cgroup v1 中,实际上无法压缩内存。由于没有办法限制内存使用量,如果容器超出其内存限制,内核将通过 OOM(内存不足)杀死来终止该容器。
幸运的是,cgroup v2 带来了一种新的设计和实现,以实现对内存的全面保护。新功能依赖于 cgroups v2,大多数当前 Linux 操作系统的发行版已经提供了该功能。通过此实验性功能,Pod 和容器的服务质量扩展到不仅涵盖 CPU 时间,还涵盖内存。
它是如何工作的?
内存 QoS 使用 cgroup v2 的内存控制器来保证 Kubernetes 中的内存资源。pod 中容器的内存请求和限制用于设置内存控制器提供的特定接口 memory.min
和 memory.high
。当 memory.min
设置为内存请求时,会保留内存资源,并且内核永远不会回收这些资源;这就是内存 QoS 如何确保 Kubernetes pod 的内存可用性的方式。如果在容器中设置了内存限制,这意味着系统需要限制容器内存的使用,内存 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 级别和节点级别 cgroup 的 cgroup 层次结构,而容器 cgroup 限制由容器运行时管理。
对于内存限制,除了限制内存使用的原始方法之外,内存 QoS 还添加了一个额外的限制内存分配功能。引入了一个限制因子作为乘数(默认为 0.8)。如果将内存限制乘以该因子的结果大于内存请求,则 kubelet 将 memory.high
设置为该值并通过 CRI 使用 Unified
。如果容器未指定内存限制,则 kubelet 将改用节点可分配内存。容器级别 cgroup 中的 memory.high
设置为
i:一个 pod 中的第 i个容器
这可以帮助提高 pod 内存使用量增加时的稳定性,从而确保在内存接近内存限制时对其进行限制。
如何使用?
以下是在 Linux 节点上启用内存 QoS 的先决条件,其中一些与 Kubernetes 对 cgroup v2 的支持有关。
- 自 v1.22 以来的 Kubernetes
- 自 v1.0.0-rc93 以来的 runc;自 1.4 以来的 containerd;自 1.20 以来的 cri-o
- Linux 内核最低版本:4.15,建议版本:5.2+
- 启用 cgroupv2 或手动启用 cgroupv2 unified_cgroup_hierarchy 的 Linux 镜像
诸如 runc 和 crun 之类的 OCI 运行时已支持 cgroups v2 Unified
,并且 Kubernetes CRI 也已进行了所需的更改以支持传递 Unified
。但是,也需要 CRI 运行时支持。Alpha 阶段的内存 QoS 旨在支持 containerd 和 cri-o。相关 PR 特性:containerd-cri 支持 LinuxContainerResources.Unified #5627 已合并,并将在 containerd 1.6 中发布。CRI-O 为 1.22 实现 kube alpha 功能 #5207 仍在 WIP 中。
满足这些先决条件后,您可以启用内存 QoS 功能门(请参阅 通过配置文件设置 kubelet 参数)。
如何了解更多信息?
您可以找到更多详细信息,如下所示
如何参与?
您可以通过多种方式联系 SIG Node
您也可以直接与我联系
- GitHub / Slack:@xiaoxubeii
- 电子邮件:[email protected]