本文已超过一年。较旧的文章可能包含过时的内容。检查页面中的信息自发布以来是否已不正确。

内存资源的质量服务

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.minmemory.high。当 memory.min 设置为内存请求时,会保留内存资源,并且内核永远不会回收这些资源;这就是内存 QoS 如何确保 Kubernetes pod 的内存可用性的方式。如果在容器中设置了内存限制,这意味着系统需要限制容器内存的使用,内存 QoS 使用 memory.high 来限制接近其内存限制的工作负载,从而确保系统不会因瞬时内存分配而不堪重负。

下表详细说明了这两个参数的特定功能以及它们如何对应于 Kubernetes 容器资源。

文件描述
memory.minmemory.min 指定 cgroup 必须始终保留的最小内存量,即系统永远不会回收的内存。如果 cgroup 的内存使用量达到此下限并且无法增加,则将调用系统 OOM killer。

我们将其映射到容器的内存请求
memory.highmemory.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 的支持有关。

  1. 自 v1.22 以来的 Kubernetes
  2. 自 v1.0.0-rc93 以来的 runc;自 1.4 以来的 containerd;自 1.20 以来的 cri-o
  3. Linux 内核最低版本:4.15,建议版本:5.2+
  4. 启用 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

您也可以直接与我联系