Kubernetes v1.32 [稳定] (默认启用)Kubernetes 内存管理器 (Memory Manager) 支持为 Guaranteed QoS 类 下的 Pod 实现内存(及大页)的保证分配。
内存管理器采用一种提示生成协议,为 Pod 提供最合适的 NUMA 亲和性。内存管理器将这些亲和性提示提供给中央管理器(拓扑管理器)。根据这些提示和拓扑管理器策略,Pod 将被拒绝或准入该节点。
此外,内存管理器确保 Pod 请求的内存从最少数量的 NUMA 节点中分配。
关于 Pod 内存资源背景,请阅读 为容器和 Pod 分配内存资源。
你需要有一个 Kubernetes 集群,并且必须配置 kubectl 命令行工具以与你的集群通信。建议在至少有两个节点的集群上运行本教程,且这些节点不能作为控制平面主机。如果你还没有集群,可以通过 minikube 创建一个,或者使用以下 Kubernetes 演练场之一。
您的 Kubernetes 服务器版本必须在 v1.32 或更高版本。
要检查版本,请输入 kubectl version。
要在 Pod 规约中使内存资源与其他请求资源对齐
Kubernetes v1.32 [alpha] (默认禁用)可以通过 WindowsCPUAndMemoryAffinity 特性门控启用 Windows 支持,且需要容器运行时的支持。
Windows 上仅支持 None 和 BestEffort 策略。
对于 Linux 节点,内存管理器为 Guaranteed QoS 类下的 Pod 提供内存(及大页)的保证分配。要立即启用内存管理器,请遵循 内存管理器配置 一节中的指南,随后准备并部署一个 Guaranteed Pod,如 将 Pod 置于 Guaranteed QoS 类中 一节所示。
内存管理器是一个提示提供者,它为拓扑管理器提供拓扑提示,拓扑管理器随后根据这些拓扑提示对请求的资源进行对齐。在 Linux 上,它还为 Pod 强制执行 cgroups(特别是 cpuset.mems)。关于 Pod 准入和部署流程的完整流程图如下所示
在此过程中,内存管理器会更新存储在 [节点映射和内存映射][2] 中的内部计数器,以管理保证内存分配。
如果节点管理员为 kubelet 配置了 reservedMemory(见 预留内存配置),内存管理器将在 kubelet 启动期间激活。在这种情况下,kubelet 会更新其节点映射以反映此预留。
当配置了 Static 策略时,您必须为节点配置预留内存(例如,在 kubelet 配置中使用 reservedMemory 配置字段)。
在内存管理器运行背景下的一个重要主题是 NUMA 组的管理。每当 Pod 的内存请求超过单个 NUMA 节点的容量时,内存管理器就会尝试创建一个包含多个 NUMA 节点并具备扩展内存容量的组。
其他管理器应该已经配置完成(参见 资源对齐前提条件)。在 kubelet 配置 中设置 memoryManagerPolicy 配置字段为您选择的 策略 名称。
可选地,可以为系统或 kubelet 进程预留一定量的内存以提高节点稳定性(见 预留内存配置)。
Kubernetes 的内存管理器提供了三种策略。您可以通过 kubelet 配置中的 memoryManagerPolicy 配置字段选择策略;Kubernetes 1.36 中可用的值为
None (默认值)Static (仅限 Linux)BestEffort (仅限 Windows)这是默认策略,不会以任何方式影响内存分配。它的作用与内存管理器完全不存在时相同。
None 策略返回默认的拓扑提示。此特殊提示表示提示提供者(在本例中为内存管理器)对任何资源的 NUMA 亲和性都没有偏好。
Kubernetes v1.32 [稳定] (默认启用)此策略仅在 Linux 上受支持。
对于 Guaranteed Pod,Static 内存管理器策略会返回与可以保证内存的 NUMA 节点集相关的拓扑提示,并通过更新内部 [NodeMap][2] 对象来预留内存。
对于 BestEffort 或 Burstable Pod,Static 内存管理器策略会返回默认的拓扑提示,因为没有对保证内存的请求,并且不会在内部 [NodeMap][2] 对象中预留内存。
此策略仅在 Linux 上受支持。
Kubernetes v1.32 [alpha] (默认禁用)此策略仅在 Windows 上受支持。
在 Windows 上,NUMA 节点分配的工作方式与 Linux 不同。没有任何机制可以确保内存访问仅来自特定的 NUMA 节点。相反,Windows 操作系统调度程序会根据 CPU 分配选择最优的 NUMA 节点。如果 Windows 调度程序认为其他 NUMA 节点最优,Windows 可能会使用这些节点。
该策略确实会通过内部节点映射跟踪可用和已请求的内存量。在进行资源分配之前,内存管理器会尽最大努力确保 NUMA 节点上有足够的可用内存。
这意味着在大多数情况下,内存分配应该按指定方式工作。
作为管理员,您可以配置节点的预留内存总量。该预置值随后用于计算提供给 Pod 的实际 可分配节点 (node allocatable) 内存量。
Kubernetes 调度程序会将可分配内存信息纳入考量以优化 Pod 调度。节点可分配机制通常被节点管理员用于为 kubelet 或操作系统进程预留 K8s 节点系统资源,以帮助确保节点稳定性。
相关的 kubelet 设置包括 kubeReserved、systemReserved 和 reservedMemory。reservedMemory 设置允许您拆分总预留内存并将其分配给多个 NUMA 节点。
您可以为每个 NUMA 节点指定逗号分隔的内存预留列表(针对不同类型的内存)。您还可以使用分号作为分隔符,指定跨越多个 NUMA 节点的预留。
内存管理器不会将此预留内存用于运行容器工作负载。
例如,如果您有一个可用内存为 10GiB 的 NUMA 节点 "NUMA0",并且您配置 reservedMemory 为 NUMA0 预留 1Gi(内存),则内存管理器会假设只有 9GiB 可供 Pod 使用。
您可以省略此参数,但请注意,所有 NUMA 节点的预留内存总量应等于节点可分配内存总量。
如果至少有一个节点可分配参数不为零,则需要为至少一个 NUMA 节点指定 reservedMemory。事实上,evictionHard 阈值默认等于 100Mi,因此如果您使用 Static 策略,则指定 reservedMemory 是强制性的。
以下是如何为 kubelet 设置 reservedMemory 配置的一些示例。
# Example 1
reservedMemory:
- numaNode: 0 # NUMA node index
limits:
memory: "1Gi" # byte quantity
- numaNode: 1
limits:
memory: "2Gi" # byte quantity
# Example 2
reservedMemory:
- numaNode: 0
limits:
"memory": "512Gi"
- numaNode: 1
limits:
"memory": "512Gi"
"hugepages-1Gi": "2Gi" # only relevant on Linux
当您指定 reservedMemory 的值时,必须使其与生效的 kubeReserved 和 systemReserved 值兼容,以及您作为 evictionHard 一部分设置的任何 memory.available 设置兼容。
如果您不遵循上述公式,内存管理器将在启动时显示错误。
换句话说,示例 1(上文)说明对于常规内存(type=memory),Kubernetes 总共预留了 3GiB;即
一些与节点可分配配置相关的 kubelet 设置示例
kubeReserved: { cpu: "500m", memory: "50Mi" } # half a CPU, 50MiB of memory
systemReserved: { cpu: "500m", memory: "256Mi" } # half a CPU, 256MiB of memory
默认的硬驱逐阈值为 100MiB,且不是零。请记得通过设置 reservedMemory 将预留的内存量增加该硬驱逐阈值。否则,kubelet 将不会启动内存管理器并显示错误。
这是一个使用 reservedMemory 的正确配置示例
# this snippet relies on the default value of evictionHard
memoryManagerPolicy: Static
kubeReserved: { cpu: "4", memory: "4Gi" }
systemReserved: { cpu: "1", memory: "1Gi" }
reservedMemory:
- numaNode: 0
limits:
memory: "3Gi"
- numaNode: 1
limits:
memory: "2148Mi" # 3GiB minus 100MiB
避免以下配置
memory 或 hugepages-<size> 不同(特定 <size> 的大页也应该存在)。如果选择的策略不是 None,内存管理器会识别处于 Guaranteed QoS 类中的 Pod。对于每个 Guaranteed Pod,内存管理器会向拓扑管理器提供特定的拓扑提示。对于 Guaranteed 之外 QoS 类的 Pod,内存管理器会向拓扑管理器提供默认的拓扑提示。
以下 Pod 清单摘录将 Pod 分配给 Guaranteed QoS 类。
当 requests 等于 limits 时,带有整数 CPU 的 Pod 在 Guaranteed QoS 类中运行
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
example.com/device: "1"
requests:
memory: "200Mi"
cpu: "2"
example.com/device: "1"
同样,当 requests 等于 limits 时,共享 CPU 的 Pod 也在 Guaranteed QoS 类中运行。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "300m"
example.com/device: "1"
requests:
memory: "200Mi"
cpu: "300m"
example.com/device: "1"
注意,Pod 必须指定 CPU 和内存请求,才能将其纳入 Guaranteed QoS 类。