本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
内存资源的服务质量
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 选择一个节点来运行。每个节点对每种资源类型都有最大容量:它可以为 Pods 提供的 CPU 和内存量。调度器确保,对于每种资源类型,已调度的容器的资源请求总和小于节点的容量。
spec.containers[].resources.limits
在 kubelet 启动容器时传递给容器运行时。CPU 被认为是“可压缩”资源。如果您的应用程序开始达到 CPU 限制,Kubernetes 会开始限制您的容器,从而可能导致您的应用程序性能下降。但是,它不会被终止。这就是“可压缩”的含义。
在 cgroup v1 中,并且在该功能之前,容器运行时从未考虑并有效地忽略了 spec.containers[].resources.requests["memory"]
。这与 CPU 不同,在 CPU 中,容器运行时会同时考虑请求和限制。此外,cgroup v1 中的内存实际上无法压缩。由于无法限制内存使用,如果容器超过其内存限制,它将被内核通过 OOM (Out Of Memory) 杀死而终止。
幸运的是,cgroup v2 带来了新的设计和实现,以实现内存的全面保护。新功能依赖于 cgroups v2,大多数当前发布的 Linux 操作系统都已提供该功能。通过这项实验性功能,Pod 和容器的服务质量扩展到不仅涵盖 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 v1.4 及更高版本;cri-o v1.20 及更高版本
- Linux 内核最低版本:4.15,推荐版本:5.2+
- 启用 cgroupv2 的 Linux 镜像或手动启用 cgroupv2 unified_cgroup_hierarchy
OCI 运行时(如 runc 和 crun)已经支持 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 仍在进行中。
满足这些先决条件后,您可以启用内存 QoS 功能门(请参阅通过配置文件设置 kubelet 参数)。
我如何了解更多信息?
您可以找到更多详细信息如下:
我如何参与?
你可以通过多种方式联系 SIG Node
- Slack: #sig-node
- 邮件列表
- 开放的社区问题/PR
您也可以直接联系我
- GitHub / Slack: @xiaoxubeii
- 电子邮件:xiaoxubeii@gmail.com