本页介绍了 Kubernetes 中的服务质量 (QoS) 类,并解释了 Kubernetes 如何根据您为 Pod 中容器指定的资源约束为每个 Pod 分配 QoS 类。Kubernetes 依靠这种分类来决定当节点上可用资源不足时应该驱逐哪些 Pod。
Kubernetes 会对您运行的 Pod 进行分类,并将每个 Pod 分配到特定的服务质量 (QoS) 类中。Kubernetes 使用该分类来影响不同 Pod 的处理方式。Kubernetes 根据 Pod 中 容器 的 资源请求(Requests) 以及这些请求与资源限制(Limits)的关系来进行此分类。这被称为 服务质量 (QoS) 类。Kubernetes 根据 Pod 内各个容器的资源请求和限制为每个 Pod 分配 QoS 类。Kubernetes 使用 QoS 类来决定在节点遭遇 节点压力 时应驱逐哪些 Pod。可能的 QoS 类有 Guaranteed、Burstable 和 BestEffort。当节点资源耗尽时,Kubernetes 会首先驱逐该节点上运行的 BestEffort Pod,其次是 Burstable Pod,最后是 Guaranteed Pod。当这种驱逐是由资源压力引起时,只有超过资源请求的 Pod 才会成为驱逐对象。
Guaranteed 级别的 Pod 具有最严格的资源限制,最不容易被驱逐。它们保证在超过其限制或没有可从节点抢占的较低优先级 Pod 之前不会被终止。它们不能获取超过其指定限制的资源。这些 Pod 还可以使用 static CPU 管理策略来利用独占 CPU。
要使 Pod 被赋予 Guaranteed QoS 类:
如果 Pod 使用的是 Pod 级资源:
Kubernetes v1.34 [beta](默认启用)Burstable 级别的 Pod 根据请求具有一定的资源下限保证,但不需要特定的限制。如果未指定限制,它默认为等同于节点容量的限制,这允许 Pod 在有资源可用时灵活地增加其资源使用量。在因节点资源压力导致的 Pod 驱逐事件中,这些 Pod 仅在所有 BestEffort Pod 被驱逐后才会被驱逐。由于 Burstable Pod 可能包含没有资源限制或请求的容器,因此 Burstable Pod 可能会尝试使用任意数量的节点资源。
如果满足以下条件,Pod 将被赋予 Burstable QoS 类:
Guaranteed QoS 类的标准。BestEffort QoS 类中的 Pod 可以使用未专门分配给其他 QoS 类 Pod 的节点资源。例如,如果您有一个具有 16 个 CPU 核心供 kubelet 使用的节点,并且您将 4 个 CPU 核心分配给了 Guaranteed Pod,那么 BestEffort QoS 类中的 Pod 就可以尝试使用剩余 12 个 CPU 核心中的任意数量。
如果节点面临资源压力,kubelet 会优先驱逐 BestEffort Pod。
如果一个 Pod 不符合 Guaranteed 或 Burstable 的标准,则其 QoS 类为 BestEffort。换句话说,只有当 Pod 中的容器都没有内存限制或内存请求,且都没有 CPU 限制或 CPU 请求,并且该 Pod 没有任何 Pod 级内存或 CPU 限制或请求时,Pod 才是 BestEffort。Pod 中的容器可以请求其他资源(非 CPU 或内存),并仍然被归类为 BestEffort。
Kubernetes v1.22 [alpha](默认禁用)内存 QoS 使用 cgroup v2 的内存控制器来管理 Kubernetes 中的内存限制和保护。它利用 Pod 的 QoS 类来决定应用哪些 cgroup 设置,但这是一个可选的独立特性。禁用内存 QoS 不会改变 Pod 的分类方式。
对于 Burstable Pod,kubelet 会设置 memory.high 以在工作负载达到其硬限制 (memory.max) 之前对其内存分配进行限制。限制阈值的计算方式如下:
memory.high = requests + memoryThrottlingFactor * (limits - requests)
其中 memoryThrottlingFactor 默认值为 0.9。例如,一个内存请求为 256 MiB 且限制为 1 GiB 的容器,其 memory.high 将被设置为约 947 MiB。如果 Burstable 容器没有内存限制,则使用节点的可分配内存来代替限制。
Guaranteed Pod 不会获得 memory.high,因为它们的请求等于其限制。BestEffort Pod 也不会获得 memory.high,因为它们没有请求或限制。
内存预留通过 kubelet 配置字段 memoryReservationPolicy 进行控制:
None(默认):kubelet 不会为容器和 Pod 设置 memory.min 或 memory.low。没有任何内存被内核硬锁定。TieredReservation:kubelet 根据 Pod 的 QoS 类设置分层内存保护:memory.min 设置为内存请求量。在任何情况下,内核都不会回收此内存。memory.low 设置为内存请求量。内核会优先保留此内存,但在极端压力下可能会回收它。内存 QoS 需要使用 cgroup v2 的 Linux 内核。建议使用内核 5.9 或更高版本,因为在旧版本内核上进行 memory.high 限制可能会触发已知的 livelock(活锁)错误。如果 MemoryQoS 特性开关在较旧的内核上启用,kubelet 会在启动时记录警告信息。
某些行为与 Kubernetes 分配的 QoS 类无关。例如:
任何超过资源限制的容器都将被 kubelet 杀死并重启,且不会影响该 Pod 中的其他容器。
如果一个容器超过了其资源请求,且其运行的节点面临资源压力,则该容器所属的 Pod 将成为 驱逐 对象。如果发生这种情况,Pod 中的所有容器都将被终止。Kubernetes 可能会创建一个替换 Pod,通常是在另一个节点上。
Pod 的资源请求等于其各组件容器资源请求之和,Pod 的资源限制等于其各组件容器资源限制之和。
kube-scheduler 在选择 抢占 哪些 Pod 时不考虑 QoS 类。当集群没有足够的资源来运行您定义的所有 Pod 时,可能会发生抢占。
QoS 类是在 Pod 创建时确定的,并在 Pod 的生命周期内保持不变。如果您稍后尝试进行会导致不同 QoS 类的 原地调整大小 (in-place resize),该调整请求将被准入控制拒绝。