为系统守护进程保留计算资源

Kubernetes 节点可以调度到 `Capacity`。默认情况下,Pod 可以占用节点上所有可用容量。这是一个问题,因为节点通常运行许多系统守护进程来驱动操作系统和 Kubernetes 本身。除非为这些系统守护进程预留资源,否则 Pod 和系统守护进程会争夺资源,导致节点上的资源饥饿问题。

`kubelet` 暴露了一个名为“Node Allocatable”(节点可分配)的功能,有助于为系统守护进程预留计算资源。Kubernetes 建议集群管理员根据每个节点上的工作负载密度配置“Node Allocatable”。

准备工作

你需要有一个 Kubernetes 集群,并且 kubectl 命令行工具已配置为与你的集群通信。建议在至少有两个节点(不充当控制平面主机)的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者使用这些 Kubernetes 演练场之一。

你可以使用 kubelet 配置文件 配置以下 kubelet 配置设置

节点可分配(Node Allocatable)

node capacity

Kubernetes 节点上的“Allocatable”(可分配)定义为可用于 Pod 的计算资源量。调度器不会超额分配“Allocatable”。目前支持“CPU”、“内存”和“临时存储”。

Node Allocatable 作为 API 中 `v1.Node` 对象的一部分,以及 CLI 中 `kubectl describe node` 的一部分公开。

可以在 `kubelet` 中为两类系统守护进程预留资源。

启用 QoS 和 Pod 级别 cgroup

为了在节点上正确实施节点可分配约束,你必须通过 `cgroupsPerQOS` 设置启用新的 cgroup 层次结构。此设置默认启用。启用后,`kubelet` 将把所有最终用户 Pod 放在由 `kubelet` 管理的 cgroup 层次结构下。

配置 cgroup 驱动程序

`kubelet` 支持使用 cgroup 驱动程序操纵主机上的 cgroup 层次结构。该驱动程序通过 `cgroupDriver` 设置进行配置。

支持的值如下:

  • `cgroupfs` 是默认驱动程序,它通过直接操纵主机上的 cgroup 文件系统来管理 cgroup 沙盒。
  • `systemd` 是一个替代驱动程序,它使用瞬态切片(transient slices)管理 cgroup 沙盒,以支持该 init 系统所支持的资源。

根据相关容器运行时的配置,操作员可能需要选择特定的 cgroup 驱动程序以确保系统行为正确。例如,如果操作员使用 `containerd` 运行时提供的 `systemd` cgroup 驱动程序,则 `kubelet` 必须配置为使用 `systemd` cgroup 驱动程序。

Kube 预留

  • KubeletConfiguration 设置:`kubeReserved: {}`。示例值 `{cpu: 100m, memory: 100Mi, ephemeral-storage: 1Gi, pid=1000}`
  • KubeletConfiguration 设置:`kubeReservedCgroup: ""`

`kubeReserved` 旨在捕获 Kubernetes 系统守护进程(如 `kubelet`、`容器运行时` 等)的资源预留。它不用于为作为 Pod 运行的系统守护进程预留资源。`kubeReserved` 通常是节点上 `Pod 密度` 的函数。

除了 `cpu`、`memory` 和 `ephemeral-storage` 之外,还可以指定 `pid` 以便为 Kubernetes 系统守护进程预留指定数量的进程 ID。

要选择性地对 Kubernetes 系统守护进程强制执行 `kubeReserved`,请将 kube 守护进程的父控制组指定为 `kubeReservedCgroup` 设置的值,并将 `kube-reserved` 添加到 `enforceNodeAllocatable`

建议将 Kubernetes 系统守护进程放置在顶级控制组下(例如,在 systemd 机器上为 `runtime.slice`)。每个系统守护进程理想情况下应在其自己的子控制组中运行。有关建议的控制组层次结构的更多详细信息,请参阅设计提案

请注意,如果 `kubeReservedCgroup` 不存在,Kubelet 不会创建它。如果指定了无效的 cgroup,kubelet 将无法启动。使用 `systemd` cgroup 驱动程序时,应遵循特定模式来定义 cgroup 的名称:该名称应是你为 `kubeReservedCgroup` 设置的值,并附加 `.slice`。

系统预留

  • KubeletConfiguration 设置:`systemReserved: {}`。示例值 `{cpu: 100m, memory: 100Mi, ephemeral-storage: 1Gi, pid=1000}`
  • KubeletConfiguration 设置:`systemReservedCgroup: ""`

`systemReserved` 旨在捕获 OS 系统守护进程(如 `sshd`、`udev` 等)的资源预留。`systemReserved` 也应为 `kernel` 预留 `memory`,因为目前 Kubernetes 中不将 `kernel` 内存计入 Pod。还建议为用户登录会话预留资源(在 systemd 中为 `user.slice`)。

除了 `cpu`、`memory` 和 `ephemeral-storage` 之外,还可以指定 `pid` 以便为 OS 系统守护进程预留指定数量的进程 ID。

要选择性地对系统守护进程强制执行 `systemReserved`,请将 OS 系统守护进程的父控制组指定为 `systemReservedCgroup` 设置的值,并将 `system-reserved` 添加到 `enforceNodeAllocatable`

建议将操作系统系统守护进程放置在顶级控制组下(例如,在 systemd 机器上为 `system.slice`)。

请注意,如果 `systemReservedCgroup` 不存在,`kubelet` 不会创建它。如果指定了无效的 cgroup,`kubelet` 将失败。使用 `systemd` cgroup 驱动程序时,应遵循特定模式来定义 cgroup 的名称:该名称应是你为 `systemReservedCgroup` 设置的值,并附加 `.slice`。

显式预留 CPU 列表

功能状态: `Kubernetes v1.17 [稳定]`

KubeletConfiguration 设置:`reservedSystemCPUs:`。示例值 `0-3`

`reservedSystemCPUs` 旨在为 OS 系统守护进程和 Kubernetes 系统守护进程定义一个明确的 CPU 集合。`reservedSystemCPUs` 适用于不打算为 OS 系统守护进程和 Kubernetes 系统守护进程在 cpuset 资源方面定义单独的顶级 cgroup 的系统。如果 Kubelet 没有 `kubeReservedCgroup` 和 `systemReservedCgroup`,则 `reservedSystemCPUs` 提供的明确 cpuset 将优先于 `kubeReservedCgroup` 和 `systemReservedCgroup` 选项定义的 CPU。

此选项专为电信/NFV 用例设计,在这些用例中,不受控制的中断/计时器可能会影响工作负载性能。你可以使用此选项为系统/Kubernetes 守护进程以及中断/计时器定义明确的 cpuset,这样系统上的其余 CPU 就可以专门用于工作负载,受不受控制的中断/计时器的影响较小。要将系统守护进程、Kubernetes 守护进程以及中断/计时器移动到此选项定义的明确 cpuset,应使用 Kubernetes 之外的其他机制。例如:在 Centos 中,你可以使用 tuned 工具集来完成此操作。

逐出阈值

KubeletConfiguration 设置:`evictionHard: {memory.available: "100Mi", nodefs.available: "10%", nodefs.inodesFree: "5%", imagefs.available: "15%"}`。示例值:`{memory.available: "<500Mi"}`

节点级别的内存压力会导致系统 OOM,这会影响整个节点和其上运行的所有 Pod。节点可能会暂时离线,直到内存被回收。为了避免(或降低可能性)系统 OOM,kubelet 提供了资源不足管理。驱逐仅支持 `memory` 和 `ephemeral-storage`。通过 `evictionHard` 设置预留一些内存,`kubelet` 会在节点上的内存可用性低于预留值时尝试驱逐 Pod。假设节点上不存在系统守护进程,Pod 不能使用超过 `capacity - eviction-hard` 的资源。因此,为驱逐预留的资源不适用于 Pod。

强制执行节点可分配

KubeletConfiguration 设置:`enforceNodeAllocatable: [pods]`。示例值:`[pods,system-reserved,kube-reserved]`

调度器将“Allocatable”视为 Pod 的可用 `capacity`。

默认情况下,`kubelet` 会对所有 Pod 强制执行“Allocatable”。当所有 Pod 的总使用量超过“Allocatable”时,通过驱逐 Pod 来执行此操作。有关驱逐策略的更多详细信息,请参见节点压力驱逐页面。此强制执行通过将 `pods` 值指定给 KubeletConfiguration 设置 `enforceNodeAllocatable` 来控制。

可以选择性地让 `kubelet` 通过在同一设置中指定 `kube-reserved` 和 `system-reserved` 值来强制执行 `kubeReserved` 和 `systemReserved`。请注意,要强制执行 `kubeReserved` 或 `systemReserved`,需要分别指定 `kubeReservedCgroup` 或 `systemReservedCgroup`。

通用指南

系统守护进程应被视为与Guaranteed Pods 类似。系统守护进程可以在其限制控制组内突发,此行为需要作为 Kubernetes 部署的一部分进行管理。例如,`kubelet` 应该有自己的控制组,并与容器运行时共享 `kubeReserved` 资源。但是,如果强制执行 `kubeReserved`,Kubelet 就不能突发并用尽所有可用的节点资源。

在强制执行 `systemReserved` 预留时要格外小心,因为它可能导致关键系统服务 CPU 饥饿、OOM 终止或无法在节点上派生。建议仅在用户对节点进行了详尽的分析以得出精确估计并有信心在组中任何进程 OOM 终止时恢复的情况下,才强制执行 `systemReserved`。

  • 首先对 `pods` 强制执行“Allocatable”。
  • 一旦建立足够的监控和警报来跟踪 kube 系统守护进程,尝试根据使用启发式方法强制执行 `kubeReserved`。
  • 如果绝对必要,随着时间的推移强制执行 `systemReserved`。

随着越来越多的功能添加,kube 系统守护进程的资源需求可能会随着时间增长。随着时间的推移,Kubernetes 项目将尝试降低节点系统守护进程的利用率,但目前这不是一个优先事项。因此,预计未来版本中 `Allocatable` 容量会下降。

示例场景

以下是一个说明节点可分配计算的示例

  • 节点有 `32Gi` 内存、`16 个 CPU` 和 `100Gi` 存储
  • `kubeReserved` 设置为 `{cpu: 1000m, memory: 2Gi, ephemeral-storage: 1Gi}`
  • `systemReserved` 设置为 `{cpu: 500m, memory: 1Gi, ephemeral-storage: 1Gi}`
  • `evictionHard` 设置为 `{memory.available: "<500Mi", nodefs.available: "<10%"}`

在这种情况下,“Allocatable”将是 14.5 个 CPU,28.5Gi 内存和 `88Gi` 本地存储。调度器确保该节点上所有 Pod 的总内存 `requests` 不超过 28.5Gi,存储不超过 88Gi。当 Pod 的总内存使用量超过 28.5Gi 或总磁盘使用量超过 88Gi 时,Kubelet 将驱逐 Pod。如果节点上的所有进程都尽可能地消耗 CPU,Pod 总共不能消耗超过 14.5 个 CPU。

如果未强制执行 `kubeReserved` 和/或 `systemReserved` 且系统守护进程超出其预留,当节点总内存使用量高于 31.5Gi 或 `存储` 大于 90Gi 时,`kubelet` 将驱逐 Pod。

上次修改时间:2024 年 6 月 4 日太平洋标准时间凌晨 3:39:改进“为系统守护进程预留计算资源”文档 (#45771) (bc35539293)