Kubernetes 的优势之一是调度。它可以处理应用程序 Pod 在集群节点中的放置及其资源分配,因此您无需担心自己平衡资源。当资源耗尽时,Kubernetes 可以驱逐 Pod——但 Kubernetes 如何决定驱逐哪个 Pod 呢?
Kubernetes Pod 和资源
虽然一个 Pod 可以容纳多个容器,但为了本文的目的,我将它们作为一个单独的对象进行讨论。
在 Kubernetes 中,您可以定义 Pod 对 CPU(计算)和内存的需求。CPU 以单位衡量:1 个 CPU 等于 1 个云 vCPU 或裸机上的 1 个超线程。内存以字节为单位衡量(例如,Mi 代表兆字节,Gi 代表千兆字节,等等)。
Pod 执行所需的最小资源量在 YAML 的 requests 部分中定义。为了防止使用节点的所有资源,YAML 的 limits 部分定义了最大资源使用量。这是一个示例
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
当 Kubernetes 调度器想要将 Pod 放置在节点上时,它首先确认哪个节点具有可用的资源来满足其请求。注意:如果您的节点上有未定义请求的 Pod,Kubernetes 将不会考虑它们,这可能会导致故障。
资源有两种类型:弹性资源和精确资源。CPU 是一种弹性资源,可以超额配置。即使应用程序没有获得请求的 CPU 资源,它们也可以继续运行,但性能会降低。另一方面,内存是一种精确资源:应用程序无法在没有请求的量的情况下运行。如果我的 Pod 请求 1G 内存,但只能获得 0.8G,则当它尝试分配全部内存时,会因内存分配错误而失败。
Limits 的功能与 requests 不同。Limits 仅在节点 CPU 负载过高时(即 CPU 使用率达到 100%)才适用于 CPU。这是一种常见情况,本地节点操作系统可以处理它。但是,如果 Pod 超出了其内存限制,它将被内存不足 (OOM) 杀手终止。
何时发生驱逐?
这种差异与 Kubernetes 处理资源压力的方式有关。如果节点资源耗尽,Kubernetes 需要驱逐 Pod,这种事件称为节点压力驱逐。当 CPU 完全利用时,节点调度器可以处理它,因此不会发生驱逐。但是,如果可用内存不足,则需要从节点中驱逐 Pod 并尝试将它们放置在另一个节点中。这称为由于内存压力而导致的驱逐。磁盘空间不足也可能导致节点压力驱逐。
Kubernetes 如何决定驱逐哪些 Pod?
Pod 的驱逐取决于导致节点压力的资源,例如内存或磁盘空间。首先要驱逐的是处于失败状态的 Pod,因为它们没有运行,但仍可能在使用资源。在此之后,Kubernetes 会评估正在运行的 Pod。
驱逐消耗最多内存的 Pod 行不通,因为它很可能是一个活动的 Pod,并且更难放置。相反,Kubernetes 会查看两个不同的类别来做出此决定:QoS(服务质量)类和优先级类。
QoS 类
Kubernetes 有三个可以分配给 Pod 的 QoS 类
Guaranteed(保证):对于 Pod 中的每个容器
- 必须有内存限制和内存请求。
- 内存限制必须等于内存请求。
- 必须有 CPU 限制和 CPU 请求。
- CPU 限制必须等于 CPU 请求。
Burstable(突发):Pod 不符合 QoS 类 Guaranteed 的标准,但 Pod 中至少有一个容器具有内存或 CPU 请求
BestEffort(尽力而为):Pod 必须没有任何容器具有内存或 CPU 限制或请求。
Pod QoS 类由其最低容器 QoS 类决定。
优先级类
Pod 的优先级类定义了 Pod 相对于集群中运行的其他 Pod 的重要性:优先级越高,Pod 越重要。Kubernetes 在尝试调度 Pod 时使用优先级类。如果无法调度,它将驱逐优先级较低的 Pod,以便为其腾出空间。
您可以使用以下类别设置 Pod 抢占(驱逐)策略
- Never(永不):此 Pod 具有高优先级,但 Kubernetes 不应驱逐其他 Pod 来运行它。此 Pod 可以被驱逐以运行更高优先级的 Pod。
- PreemptLowerPriority(抢占较低优先级):驱逐优先级较低的 Pod 以运行此 Pod
Pod 优先级类由其最低容器优先级类决定。
云平台 OKD(以前称为 Minishift,是 Red Hat OpenShift 的基础)具有三个内置优先级类
- system-node-critical(系统节点关键):永远不应从节点中驱逐的 Pod
- system-cluster-critical(系统集群关键):对集群很重要且可以从节点中驱逐的 Pod,但仅在特定情况下
- cluster-logging(集群日志记录):必须优先于其他应用程序调度的 Pod
使用类对驱逐进行排序
对于磁盘压力,Kubernetes 仅使用 Pod 的优先级类对其驱逐进行排序,因为在调度 Pod 之前没有预先请求资源量的机制。因此,使用基于 CSI 的本地持久卷而不是主机路径来存储 Pod 的数据非常重要。
对于内存压力,Kubernetes 将尝试驱逐那些使用量超过请求的 Pod,同时考虑 Pod 的优先级类,顺序如下
- QoS 类为 BestEffort 的 Pod 没有任何请求,因此始终被考虑驱逐。
- 如果在驱逐 BestEffort 类 Pod 后压力仍然存在,则根据 Pod 的优先级类驱逐 Pod。具有相同优先级的 Pod 根据其使用级别超过请求的量来驱逐。
- 如果仍然存在压力,Kubernetes 将考虑驱逐 Guaranteed Pod 和未超出请求的 Burstable Pod。这些 Pod 根据其优先级驱逐。
防止 Pod 驱逐
如何降低您的重要 Pod 被驱逐的几率?
- 始终分配优先级类,因为 Kubernetes 会同时考虑内存压力和磁盘压力。
- 避免使用 QoS 类为 BestEffort 的 Pod。
- 对于内存使用量固定的 Pod,请使用 Guaranteed QoS 类。我不建议对每个 Pod 都使用它,因为它可能导致内存使用效率低下。大多数应用程序在加载时会使用最多的内存。将请求设置为等于限制可能意味着设置更高的请求以允许 Pod 获得最大内存量,或者降低限制以使您的应用程序不会获得更多内存。
如果您有兴趣了解更多关于 Pod 调度和驱逐的信息,您可以浏览 Kubernetes 文档
评论已关闭。