Atlantis
GitHub Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

3. 节点压力驱逐

1. 前言

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

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

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

以上是 kubernetes 官方文档介绍内容,之前遇到了一些 OOM、磁盘压力问题需要对客户做解释,排查过程中梳理了一些资料,这里做一个记录。

官方文档:节点压力驱逐

2. 驱逐信号

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

kubelet 使用以下驱逐信号:

驱逐信号 描述
memory.available memory.available := node.status.capacity[memory] - node.stats.memory.workingSet
nodefs.available nodefs.available := node.stats.fs.available
nodefs.inodesFree nodefs.inodesFree := node.stats.fs.inodesFree
imagefs.available imagefs.available := node.stats.runtime.imagefs.available
imagefs.inodesFree imagefs.inodesFree := node.stats.runtime.imagefs.inodesFree
pid.available pid.available := node.stats.rlimit.maxpid - node.stats.rlimit.curproc
  1. memory.available 的值来自 cgroupfs,资源不足的判定是基于 cgroup 层次结构中的用户 Pod 所处的局部及 cgroup 根节点作出的
  2. nodefs:节点的主要文件系统,用于本地磁盘卷、emptyDir、日志存储等。 例如,nodefs 包含 /var/lib/kubelet/。
  3. imagefs:可选文件系统,供容器运行时存储容器镜像和容器可写层,例如,/var/lib/docker/。

3. 驱逐条件

3.1 软驱逐条件

软驱逐条件将驱逐条件与管理员所必须指定的宽限期配对。 在超过宽限期之前,kubelet 不会驱逐 Pod。

由 eviction-soft、eviction-soft-grace-period、eviction-max-pod-grace-period 构成,分别代表:驱逐条件、驱逐宽限期、在满足软驱逐条件而终止 Pod 时使用的最大允许宽限期(以秒为单位)。

3.2 硬驱逐条件

由eviction-hard定义,当达到硬驱逐条件时, kubelet 会立即杀死 pod。

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

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

3.3 检测间隔

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

4. 节点条件

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

节点条件 驱逐信号 描述
MemoryPressure memory.available 节点上的可用内存已满足驱逐条件
DiskPressure nodefs.available、nodefs.inodesFree、imagefs.available 或 imagefs.inodesFree 节点的根文件系统或镜像文件系统上的可用磁盘空间和 inode 已满足驱逐条件
PIDPressure pid.available (Linux) 节点上的可用进程标识符已低于驱逐条件

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

5. 文件系统资源回收

kubelet 在驱逐最终用户 Pod 之前会先尝试回收节点级资源。当报告 DiskPressure 节点状况时,kubelet 会根据节点上的文件系统回收节点级资源。

存在imagefs

如果节点有一个专用的 imagefs 文件系统供容器运行时使用,kubelet 会执行以下操作:

  1. 如果 nodefs 文件系统满足驱逐条件,kubelet 垃圾收集死亡 Pod 和容器。
  2. 如果 imagefs 文件系统满足驱逐条件,kubelet 将删除所有未使用的镜像。

不存在imagefs

如果节点只有一个满足驱逐条件的 nodefs 文件系统, kubelet 按以下顺序释放磁盘空间:

  1. 对死亡的 Pod 和容器进行垃圾收集
  2. 删除未使用的镜像

6. kubelet 驱逐时Pod的选择

kubelet 使用以下参数来确定 Pod 驱逐顺序:

  1. Pod 的资源使用是否超过其请求
  2. Pod 优先级
  3. Pod 相对于请求的资源使用情况

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

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

6.1 内存压力

Pod的QoS分类:

  1. Guaranteed:Pod 中的每个容器都必须指定request和limit,且request等于limit
  2. Burstable:Pod 中至少一个 Container 设置了limits,允许使用超过request限制的资源
  3. BestEffort:Pod 中的 Container 没有设置request和limit

如果节点在 kubelet 能够回收内存之前遇到内存不足(OOM)事件, 则节点依赖 oom_killer 来响应。

kubelet 根据 Pod 的服务质量(QoS)为每个容器设置一个 oom_score_adj 值。

服务质量 oom_score_adj
Guaranteed -997
BestEffort 1000
Burstable min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)
kubelet 还会将具有 system-node-critical 优先级 的 Pod 中的容器 oom_score_adj 值设为 -997。

现实案例

用户进程被杀死时,可以在kubelet中看到OOM记录,且容器的lastState有OOM Killed的信息。

alt text

OOM杀死pause进程时,需要在message文件(或dmesg -T)中才能看到OOM记录,因为沙箱被Kill了,kubelet中只记录了ContainerDied。

alt text

alt text

6.2 磁盘压力(不含inode)

kubelet 根据节点是否具有专用的 imagefs 文件系统对 Pod 进行不同的排序:

存在imagefs

  1. 如果 nodefs 触发驱逐, kubelet 会根据 nodefs 使用情况(本地卷 + 所有容器的日志)对 Pod 进行排序。
  2. 如果 imagefs 触发驱逐,kubelet 会根据所有容器的可写层使用情况对 Pod 进行排序。

不存在imagefs

如果 nodefs 触发驱逐, kubelet 会根据磁盘总用量(本地卷 + 日志和所有容器的可写层)对 Pod 进行排序。

6.3 PID压力/磁盘压力(inode)

当 kubelet 因 inode 或 PID 不足而驱逐 Pod 时, 它使用优先级来确定驱逐顺序,因为 inode 和 PID 没有 requests。