Kubernetes

Kubernetes驱逐机制

2022-03-23  本文已影响0人  王勇1024

什么是节点驱逐?

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

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

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

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

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

说明:

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

两种驱逐机制

目前kubernetes中存在两种eviction机制,分别由kube-controller-managerkubelet实现。

kube-controller-manager驱逐机制

kube-controller-manager主要由多个控制器构成,而eviction的功能主要由node controller这个控制器实现。该Eviction会周期性检查所有节点状态,当节点处于NotReady状态超过一段时间后,驱逐该节点上所有pod。

kube-controller-manager提供了以下启动参数控制驱逐:

kubelet驱逐机制

如果节点处于资源压力,那么kubelet就会执行驱逐策略。驱逐会考虑Pod的优先级,资源使用和资源申请。当优先级相同时,资源使用/资源申请最大的Pod会被首先驱逐。

kube-controller-manager的驱逐机制是粗粒度的,即驱赶一个节点上的所有pod,而kubelet则是细粒度的,它驱赶的是节点上的某些Pod,驱赶哪些Pod与Pod的Qos机制有关。该Eviction会周期性检查本节点内存、磁盘等资源,当资源不足时,按照优先级驱逐部分pod。

驱逐阈值分为软驱逐阈值(Soft Eviction Thresholds)和强制驱逐(Hard Eviction Thresholds)两种机制,如下:

kubelet提供了以下参数控制eviction:

本节我们重点介绍kubelet的驱逐机制。

驱逐信号

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

kubelet 使用以下驱逐信号:

驱逐信号 Node Condition 描述
memory.available MemoryPressue memory.available := node.status.capacity[memory] - node.stats.memory.workingSet
nodefs.available DiskPressure nodefs.available := node.stats.fs.available
nodefs.inodesFree DiskPressure nodefs.inodesFree := node.stats.fs.inodesFree
imagefs.available DiskPressure imagefs.available := node.stats.runtime.imagefs.available
imagefs.inodesFree DiskPressure imagefs.inodesFree := node.stats.runtime.imagefs.inodesFree
pid.available PIDPressure pid.available := node.stats.rlimit.maxpid - node.stats.rlimit.curproc

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

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

  1. nodefs:节点的主要文件系统,用于本地磁盘卷、emptyDir、日志存储等。 例如,nodefs 包含 /var/lib/kubelet/。

  2. imagefs:可选文件系统,供容器运行时存储容器镜像和容器可写层。

kubelet 会自动发现这些文件系统并忽略其他文件系统。kubelet 不支持其他配置。

驱逐条件

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

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

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

默认驱逐条件

下面是 kubelet 默认的关于节点存储的驱逐触发条件:

nodefs.available<10%(容器 volume 使用的文件系统的可用空间,包括文件系统剩余大小和 inode 数量)

imagefs.available<15%(容器镜像使用的文件系统的可用空间,包括文件系统剩余大小和 inode 数量)

当 imagefs 使用量达到阈值时,kubelet 会尝试删除不使用的镜像来清理磁盘空间。

// DefaultEvictionHard includes default options for hard eviction.
var DefaultEvictionHard = map[string]string{
    "memory.available":  "100Mi",
    "nodefs.available":  "10%",
    "nodefs.inodesFree": "5%",
    "imagefs.available": "15%",
}

驱逐类型

软驱逐

软驱逐条件

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

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

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

硬驱逐

硬驱逐条件

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

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

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

驱逐过程

驱逐监测间隔

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

回收节点资源

kubelet 在驱逐最终用户 Pod 之前会先尝试回收节点级资源。

当报告 DiskPressure 节点状况时,kubelet 会根据节点上的文件系统回收节点级资源。

有 imagefs

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

没有 imagefs

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

  1. 对死亡的 Pod 和容器进行垃圾收集

  2. 删除未使用的镜像

垃圾回收参数

除了驱逐之外,Kubelet 还支持一系列的容器和镜像垃圾回收选项,它们未来将会被驱逐替代:

垃圾回收参数 驱逐参数 解释
--image-gc-high-threshold --eviction-hard 或 --eviction-soft 现存的驱逐回收信号可以触发镜像垃圾回收
--image-gc-low-threshold --eviction-minimum-reclaim 驱逐回收实现相同行为
--minimum-image-ttl-duration 由于驱逐不包括TTL配置,所以它还会继续支持
--maximum-dead-containers 一旦旧日志存储在容器上下文之外,就会被弃用
--maximum-dead-containers-per-container 一旦旧日志存储在容器上下文之外,就会被弃用
--minimum-container-ttl-duration 一旦旧日志存储在容器上下文之外,就会被弃用
--low-diskspace-threshold-mb --eviction-hard or eviction-soft 驱逐回收将磁盘阈值泛化到其他资源
--outofdisk-transition-frequency --eviction-pressure-transition-period 驱逐回收将磁盘压力转换到其他资源

Pod驱逐顺序

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

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

  1. Pod 的资源使用是否超过其请求

  2. Pod 优先级

  3. Pod 相对于请求的资源使用情况

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

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

  2. 资源使用量少于请求量的 Guaranteed Pod 和 Burstable Pod 根据其优先级被最后驱逐。

最小驱逐回收

在某些情况下,驱逐 Pod 只会回收少量的紧俏资源。 这可能导致 kubelet 反复达到配置的驱逐条件并触发多次驱逐。

你可以使用 --eviction-minimum-reclaim 标志或 kubelet 配置文件 为每个资源配置最小回收量。 当 kubelet 注意到某个资源耗尽时,它会继续回收该资源,直到回收到你所指定的数量为止。

例如,以下配置设置最小回收量:

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
evictionHard:
  memory.available: "500Mi"
  nodefs.available: "1Gi"
  imagefs.available: "100Gi"
evictionMinimumReclaim:
  memory.available: "0Mi"    # 没有最少回收资源限制
  nodefs.available: "500Mi"  # 最少回收 500Mi
  imagefs.available: "2Gi"   # 最少回收 2Gi

在这个例子中,如果 nodefs.available 信号满足驱逐条件, kubelet 会回收资源,直到信号达到 1Gi 的条件, 然后继续回收至少 500Mi 直到信号达到 1.5Gi。

类似地,kubelet 会回收 imagefs 资源,直到 imagefs.available 信号达到 102Gi。

对于所有资源,默认的 eviction-minimum-reclaim 为 0。

节点内存不足行为

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

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

服务质量 oom_score_adj
Guaranteed -998
BestEffort 1000
Burstable min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)

说明:

kubelet 还将具有 system-node-critical 优先级 的 Pod 中的容器 oom_score_adj 值设为 -997。

如果 kubelet 在节点遇到 OOM 之前无法回收内存, 则 oom_killer 根据它在节点上使用的内存百分比计算 oom_score, 然后加上 oom_score_adj 得到每个容器有效的 oom_score。 然后它会杀死得分最高的容器。

这意味着低 QoS Pod 中相对于其调度请求消耗内存较多的容器,将首先被杀死。

与 Pod 驱逐不同,如果容器被 OOM 杀死, kubelet 可以根据其 RestartPolicy 重新启动它。

参考文档

Kubernetes中 Pod 是怎样被驱逐的?

[Kubernetes] Eviction Manager工作原理分析

深入k8s:资源控制Qos和eviction及其源码分析

上一篇下一篇

猜你喜欢

热点阅读