节点压力驱逐是 kubelet 主动终止 Pod 以回收节点上资源的过程。

kubelet 监控集群节点的 CPU、内存、磁盘空间和文件系统的 inode 等资源。 当这些资源中的一个或者多个达到特定的消耗水平, kubelet 可以主动地使节点上一个或者多个 Pod 失效,以回收资源防止饥饿。

在节点压力驱逐期间,kubelet 将所选 Pod 的 PodPhase 设置为 Failed。这将终止 Pod。

节点压力驱逐不同于 API 发起的驱逐。

kubelet 并不理会你配置的 PodDisruptionBudget 或者是 Pod 的 terminationGracePeriodSeconds。 如果你使用了软驱逐条件,kubelet 会考虑你所配置的 eviction-max-pod-grace-period。 如果你使用了硬驱逐条件,它使用 0s 宽限期来终止 Pod。

如果 Pod 是由替换失败 Pod 的工作负载资源 (例如 StatefulSet 或者 Deployment)管理, 则控制平面或 kube-controller-manager 会创建新的 Pod 来代替被驱逐的 Pod。

说明:
kubelet 在终止最终用户 Pod 之前会尝试回收节点级资源。 例如,它会在磁盘资源不足时删除未使用的容器镜像。

kubelet 使用各种参数来做出驱逐决定,如下所示:

  • 驱逐信号
  • 驱逐条件
  • 监控间隔

1、驱逐信号

驱逐信号是特定资源在特定时间点的当前状态。 kubelet 使用驱逐信号,通过将信号与驱逐条件进行比较来做出驱逐决定, 驱逐条件是节点上应该可用资源的最小量。

kubelet 使用以下驱逐信号:

驱逐信号描述
memory.availablememory.available := node.status.capacity[memory] - node.stats.memory.workingSet
nodefs.availablenodefs.available := node.stats.fs.available
nodefs.inodesFreenodefs.inodesFree := node.stats.fs.inodesFree
imagefs.availableimagefs.available := node.stats.runtime.imagefs.available
imagefs.inodesFreeimagefs.inodesFree := node.stats.runtime.imagefs.inodesFree
pid.availablepid.available := node.stats.rlimit.maxpid - node.stats.rlimit.curproc

在上表中,描述列显示了 kubelet 如何获取信号的值。每个信号支持百分比值或者是字面值。 kubelet 计算相对于与信号有关的总量的百分比值。

memory.available 的值来自 cgroupfs,而不是像 free -m 这样的工具。 这很重要,因为 free -m 在容器中不起作用,如果用户使用 节点可分配资源 这一功能特性,资源不足的判定是基于 CGroup 层次结构中的用户 Pod 所处的局部及 CGroup 根节点作出的。 这个脚本 重现了 kubelet 为计算 memory.available 而执行的相同步骤。 kubelet 在其计算中排除了 inactive_file(即非活动 LRU 列表上基于文件来虚拟的内存的字节数), 因为它假定在压力下内存是可回收的。

kubelet 支持以下文件系统分区:

nodefs:节点的主要文件系统,用于本地磁盘卷、emptyDir、日志存储等。 例如,nodefs 包含 /var/lib/kubelet/。
imagefs:可选文件系统,供容器运行时存储容器镜像和容器可写层。
kubelet 会自动发现这些文件系统并忽略其他文件系统。kubelet 不支持其他配置。

2、驱逐条件

你可以为 kubelet 指定自定义驱逐条件,以便在作出驱逐决定时使用。

驱逐条件的形式为 [eviction-signal][operator][quantity],其中:

  • eviction-signal 是要使用的驱逐信号。
  • operator 是你想要的关系运算符, 比如 <(小于)。
  • quantity 是驱逐条件数量,例如 1Gi。 quantity 的值必须与 Kubernetes 使用的数量表示相匹配。 你可以使用文字值或百分比(%)。

例如,如果一个节点的总内存为 10Gi 并且你希望在可用内存低于 1Gi 时触发驱逐, 则可以将驱逐条件定义为 memory.available<10% 或 memory.available< 1G。 你不能同时使用二者。

你可以配置软和硬驱逐条件。

2.1 软驱逐条件

软驱逐条件将驱逐条件与管理员所必须指定的宽限期配对。 在超过宽限期之前,kubelet 不会驱逐 Pod。 如果没有指定的宽限期,kubelet 会在启动时返回错误。

你可以既指定软驱逐条件宽限期,又指定 Pod 终止宽限期的上限,,给 kubelet 在驱逐期间使用。 如果你指定了宽限期的上限并且 Pod 满足软驱逐阈条件,则 kubelet 将使用两个宽限期中的较小者。 如果你没有指定宽限期上限,kubelet 会立即杀死被驱逐的 Pod,不允许其体面终止。

你可以使用以下标志来配置软驱逐条件:

  • eviction-soft:一组驱逐条件,如 memory.available<1.5Gi, 如果驱逐条件持续时长超过指定的宽限期,可以触发 Pod 驱逐。
  • eviction-soft-grace-period:一组驱逐宽限期, 如 memory.available=1m30s,定义软驱逐条件在触发 Pod 驱逐之前必须保持多长时间。
  • eviction-max-pod-grace-period:在满足软驱逐条件而终止 Pod 时使用的最大允许宽限期(以秒为单位)。

2.2 硬驱逐条件

硬驱逐条件没有宽限期。当达到硬驱逐条件时, kubelet 会立即杀死 pod,而不会正常终止以回收紧缺的资源。

你可以使用 eviction-hard 标志来配置一组硬驱逐条件, 例如 memory.available<1Gi

kubelet 具有以下默认硬驱逐条件:

  • memory.available<100Mi
  • nodefs.available<10%
  • imagefs.available<15%
  • nodefs.inodesFree<5%(Linux 节点)

3、驱逐监测间隔

kubelet 根据其配置的 housekeeping-interval(默认为 10s)评估驱逐条件。

4、节点状态

kubelet 报告节点状况以反映节点处于压力之下,因为满足硬或软驱逐条件,与配置的宽限期无关。

kubelet 根据下表将驱逐信号映射为节点状态:

节点状态驱逐信号描述
MemoryPressurememory.available节点上的可用内存已满足驱逐条件
DiskPressure

nodefs.availablenodefs.inodesFreeimagefs.available 或 

imagefs.inodesFree

节点的根文件系统或映像文件系统上的可用磁盘空间和 inode 已满足驱逐条件
PIDPressurepid.available(Linux) 节点上的可用进程标识符已低于驱逐条件

kubelet 根据配置的 --node-status-update-frequency 更新节点条件,默认为 10s

4.1 节点条件振荡

在某些情况下,节点在软驱逐条件上下振荡,而没有保持定义的宽限期。 这会导致报告的节点条件在 true 和 false 之间不断切换,从而导致错误的驱逐决策。

为了防止振荡,你可以使用 eviction-pressure-transition-period 标志, 该标志控制 kubelet 在将节点条件转换为不同状态之前必须等待的时间。 过渡期的默认值为 5m

5、kubelet 驱逐 Pod 时的选择

如果 kubelet 回收节点级资源的尝试没有使驱逐信号低于条件, 则 kubelet 开始驱逐最终用户 Pod。

kubelet 按以下顺序排列和驱逐 Pod:

  1. 首先考虑资源使用量超过其请求的 BestEffort 或 Burstable Pod。 这些 Pod 会根据它们的优先级以及它们的资源使用级别超过其请求的程度被逐出。
  2. 资源使用量少于请求量的 Guaranteed Pod 和 Burstable Pod 根据其优先级被最后驱逐。

说明:
kubelet 不使用 Pod 的 QoS 类来确定驱逐顺序。 在回收内存等资源时,你可以使用 QoS 类来估计最可能的 Pod 驱逐顺序。 QoS 不适用于临时存储(EphemeralStorage)请求, 因此如果节点在 DiskPressure 下,则上述场景将不适用。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐