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

Kubernetes 节点可以调度到 Capacity。Pod 默认可以占用节点上所有可用容量。这是一个问题,因为节点通常会运行大量为 OS 和 Kubernetes 本身提供支持的系统守护进程。除非为这些系统守护进程预留资源,否则 Pod 和系统守护进程会争夺资源,导致节点上出现资源饥饿问题。

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

开始之前

你需要拥有一个 Kubernetes 集群,并且必须配置 kubectl 命令行工具使其与集群通信。建议你在至少有两个非控制平面主机的节点的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者使用以下某个 Kubernetes 线上训练环境:

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

节点可分配 (Node Allocatable)

node capacity

Kubernetes 节点上的“可分配”(Allocatable)被定义为可供 Pod 使用的计算资源量。调度器不会超量分配“可分配”资源。目前支持 'CPU'、'memory' 和 'ephemeral-storage'。

节点可分配(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 sandbox。
  • systemd 是另一种驱动程序,它使用该初始化系统支持的资源的 transient slice 来管理 cgroup sandbox。

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

Kube 预留 (Kube Reserved)

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

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

除了 cpumemoryephemeral-storage 之外,还可以指定 pid 来为 Kubernetes 系统守护进程预留指定数量的进程 ID。

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

建议将 Kubernetes 系统守护进程置于顶级控制组下(例如 systemd 机器上的 runtime.slice)。每个系统守护进程最好在其自己的子控制组中运行。有关推荐的控制组层级的更多详细信息,请参阅设计提案

请注意,如果 kubeReservedCgroup 不存在,Kubelet 不会创建它。如果指定了无效的 cgroup,Kubelet 将无法启动。对于 systemd cgroup 驱动程序,你应遵循特定的 cgroup 名称模式:名称应为你为 kubeReservedCgroup 设置的值,并在其后附加 .slice

系统预留 (System Reserved)

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

systemReserved 用于捕获对 OS 系统守护进程的资源预留,例如 sshdudev 等。systemReserved 也应为 kernel 预留 memory,因为当前在 Kubernetes 中,Pod 不会统计 kernel 内存。还建议为用户登录会话预留资源(systemd 世界中的 user.slice)。

除了 cpumemoryephemeral-storage 之外,还可以指定 pid 来为 OS 系统守护进程预留指定数量的进程 ID。

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

建议将 OS 系统守护进程置于顶级控制组下(例如 systemd 机器上的 system.slice)。

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

明确预留的 CPU 列表

功能状态: Kubernetes v1.17 [stable]

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

reservedSystemCPUs 用于为 OS 系统守护进程和 Kubernetes 系统守护进程定义明确的 CPU 集合。reservedSystemCPUs 适用于不打算针对 cpuset 资源为 OS 系统守护进程和 Kubernetes 系统守护进程定义独立顶级 cgroup 的系统。如果 Kubelet 没有设置 kubeReservedCgroupsystemReservedCgroup,则 reservedSystemCPUs 提供的明确 cpuset 将优先于 kubeReservedCgroupsystemReservedCgroup 选项定义的 CPU。

此选项专门为可能受到不受控制的中断/计时器影响工作负载性能的 Telco/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 提供了资源不足管理。驱逐仅支持 memoryephemeral-storage。通过 evictionHard 设置预留一些内存,kubelet 会在节点上的可用内存低于预留值时尝试驱逐 Pod。假设节点上没有系统守护进程,Pod 不能使用的资源将超过 capacity - eviction-hard。因此,为驱逐预留的资源对 Pod 不可用。

强制执行节点可分配

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

调度器将“可分配”(Allocatable)视为 Pod 的可用 capacity

kubelet 默认对所有 Pod 强制执行“可分配”。当所有 Pod 的总使用量超过“可分配”时,通过驱逐 Pod 来执行。驱逐策略的更多详细信息可以在节点压力驱逐页面找到。通过在 KubeletConfiguration 设置 enforceNodeAllocatable 中指定 pods 值来控制此强制执行。

或者,通过在同一设置中指定 kube-reservedsystem-reserved 值,可以使 kubelet 强制执行 kubeReservedsystemReserved。请注意,要强制执行 kubeReservedsystemReserved,需要分别指定 kubeReservedCgroupsystemReservedCgroup

一般指南

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

在强制执行 systemReserved 预留时要格外小心,因为它可能导致关键系统服务出现 CPU 饥饿、OOM kill 或无法在节点上 fork 进程。建议仅在用户彻底分析了其节点并得出了精确的估计,并且对其在该组中有任何进程被 OOM kill 后能够恢复充满信心的情况下,才强制执行 systemReserved

  • 首先,对 pods 强制执行“可分配”(Allocatable)。
  • 一旦建立了足够的监控和告警机制来跟踪 kube 系统守护进程,就可以尝试根据使用情况启发式地强制执行 kubeReserved
  • 如果绝对必要,随着时间的推移再强制执行 systemReserved

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

示例场景

下面是一个示例,说明节点可分配(Node Allocatable)的计算方法:

  • 节点有 32Gimemory16 CPUs100GiStorage
  • 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 或 storage 大于 90Gi 时,kubelet 会驱逐 Pod。

最后修改时间:2024 年 6 月 4 日 3:39 AM PST: Improve "Reserve Compute Resources for System Daemons" doc (#45771) (bc35539293)