为系统守护进程预留计算资源
Kubernetes 节点可以调度到 Capacity
。Pod 默认可以占用节点上所有可用容量。这是一个问题,因为节点通常会运行大量为 OS 和 Kubernetes 本身提供支持的系统守护进程。除非为这些系统守护进程预留资源,否则 Pod 和系统守护进程会争夺资源,导致节点上出现资源饥饿问题。
kubelet
提供了一项名为“节点可分配”(Node Allocatable)的功能,有助于为系统守护进程预留计算资源。Kubernetes 建议集群管理员根据每个节点上的工作负载密度配置“节点可分配”。
开始之前
你需要拥有一个 Kubernetes 集群,并且必须配置 kubectl 命令行工具使其与集群通信。建议你在至少有两个非控制平面主机的节点的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者使用以下某个 Kubernetes 线上训练环境:
你可以使用 kubelet 配置文件配置以下 kubelet 配置设置。
节点可分配 (Node Allocatable)
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 密度
的函数。
除了 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
。
系统预留 (System Reserved)
- KubeletConfiguration 设置:
systemReserved: {}
。示例值{cpu: 100m, memory: 100Mi, ephemeral-storage: 1Gi, pid=1000}
- KubeletConfiguration 设置:
systemReservedCgroup: ""
systemReserved
用于捕获对 OS 系统守护进程的资源预留,例如 sshd
、udev
等。systemReserved
也应为 kernel
预留 memory
,因为当前在 Kubernetes 中,Pod 不会统计 kernel
内存。还建议为用户登录会话预留资源(systemd 世界中的 user.slice
)。
除了 cpu
、memory
和 ephemeral-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 没有设置 kubeReservedCgroup
和 systemReservedCgroup
,则 reservedSystemCPUs
提供的明确 cpuset 将优先于 kubeReservedCgroup
和 systemReservedCgroup
选项定义的 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 提供了资源不足管理。驱逐仅支持 memory
和 ephemeral-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-reserved
和 system-reserved
值,可以使 kubelet
强制执行 kubeReserved
和 systemReserved
。请注意,要强制执行 kubeReserved
或 systemReserved
,需要分别指定 kubeReservedCgroup
或 systemReservedCgroup
。
一般指南
系统守护进程应被视为与 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)的计算方法:
- 节点有
32Gi
的memory
,16 CPUs
和100Gi
的Storage
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。