在可用计算资源较少时,kubelet为保证节点稳定性,会主动地结束一个或多个pod以回收短缺地资源,这在处理内存和磁盘这种不可压缩资源时,驱逐pod回收资源的策略,显得尤为重要。下面来具体研究下Kubelet Eviction Policy的工作机制。
在源码pkg/kubelet/eviction/api/types.go
中定义了以下及几种Eviction Signals:
Eviction Signal | Description |
---|---|
memory.available | := node.status.capacity[memory] - node.stats.memory.workingSet |
nodefs.available | := node.stats.fs.available |
nodefs.inodesFree | := node.stats.fs.inodesFree |
imagefs.available | := node.stats.runtime.imagefs.available |
imagefs.inodesFree | := node.stats.runtime.imagefs.inodesFree |
allocatableMemory.available | := pod.allocatable - pod.workingSet |
pid.available | := node.MaxPID - node.NumOfRunningProcesses |
上表主要涉及三个方面,memory、file system和pid。其中kubelet值支持2种文件系统分区:
kubelet的入参接收用户定义的eviction signal和eviction threshold的映射关系,格式如下:
[eviction-signal] [opterator] [quantity]
<
;Soft Eviction Thresholds,它与以下三个参数配合使用:
eviction-soft
:(e.g. memory.available<1.5Gi) 触发软驱逐的阈值;eviction-soft-grace-period
:(e.g. memory.available=1m30s) 当达到软驱逐的阈值,需要等待的时间;在这段时间内,每10s会重新获取监控数据并更新threshold值,如果在等待期间,最后一次的数据仍然超过阈值,才会触发驱逐pod的行为。eviction-max-pod-grace-period
:(e.g. 30s) 当满足软驱逐阈值并终止 pod 时允许的最大宽限期值。如果待Evict的Pod指定了pod.Spec.TerminationGracePeriodSeconds
,则取min(eviction-max-pod-grace-period, pod.Spec.TerminationGracePeriodSeconds)
作为Pod Termination真正的Grace Period。因此,在软驱逐策略下,从kubelet检测到驱逐信号达到了阈值设定开始,到pod真正被kill掉,共花费的时间是:sum(eviction-max-pod-grace-period, min(eviction-max-pod-grace-period, pod.Spec.TerminationGracePeriodSeconds))
Hard Eviction Thresholds比Soft Eviction Thresholds简单粗暴,没有宽限期,即使pod配置了pod.Spec.TerminationGracePeriodSeconds,一旦达到阈值配置,kubelet立马回收关联的短缺资源,并且使用的就立即结束,而不是优雅终止。此特性已经标记为Deprecated。
源码pkg/kubelet/apis/config/v1beta1/defaults_linux.go
给出了默认的硬驱逐配置:
有了驱逐信号和阈值,也有了策略,接下来就是Eviction Monitoring Interval。kubelet对应的监控周期,就通过cAdvisor的housekeeping-interval
配置的,默认10s。
kubelet监测到配置的驱逐策略被触发,会将驱逐信号映射到对应的节点状态。Kubelet会将对应的Eviction Signals映射到对应的Node Conditions,源码[pkg/kubelet/eviction/helpers.go
],其映射关系如下:
节点状态 | 驱逐信号 | 描述 |
---|---|---|
MemoryPressure | memory.avaliable, allocatableMemory.available | 节点或pod的可用内存触发驱逐阈值 |
DiskPressure | nodefs.avaliable, nodefs.inodesFree, imagefs.available, imagesfs.inodesFree | 节点的root fs或image fs上的可用磁盘空间和索引节点已满足收回阈值 |
PIDPressure | pid.available | 节点的可用PID触发驱逐阈值 |
kubelet映射了Node Condition之后,会继续按照--node-status-update-frequency
(default 10s)配置的时间间隔,周期性的与kube-apiserver进行node status updates。
考虑这样一种场景,节点上监控到soft eviction signal的值,始终在eviction threshold上下波动,那么kubelet就会将该node对应的node condition在true和false之间来回切换。给kube-scheduler产生错误的调度结果。
因此,kubelet添加参数eviction-pressure-transition-period
(default 5m0s)配置,使Kubelet在解除由Evicion Signal映射的Node Pressure之前,必须等待5分钟。
驱逐逻辑添加了一步:
Soft Evction Singal
高于Soft Eviction Thresholds
时,Kubelet还是会立刻设置对应的MemoryPressure或DiskPressure为True。Soft Evction Singal
低于Soft Eviction Thresholds
的情况,则需要等待eviction-pressure-transition-period
(default 5m0s)配置的这么长时间,才会将condition pressure切换回False。一句话总结:Node Condition Pressure成为True容易,切换回False则要等eviction-pressure-transition-period
。
如果满足驱逐阈值并超过了宽限期,kubelet将启动回收压力资源的过程,直到它发现低于设定阈值的信号为止。kubelet将尝试在驱逐终端用户 pod 前回收节点层级资源。发现磁盘压力时,如果节点针对容器运行时配置有独占的 imagefs,kubelet回收节点层级资源的方式将会不同。
kubelet根据Pod的QoS Class实现了一套默认的Evication策略,kubelet 首先根据他们对短缺资源的使用是否超过请求来排除 pod 的驱逐行为,然后通过 优先级,然后通过相对于 pod 的调度请求消耗急需的计算资源。图解如下:
对于每一种Resource都可以将容器分为3中QoS Classes: Guaranteed, Burstable, and Best-Effort,它们的QoS级别依次递减。
BestEffort
,按照短缺资源占用量排序,占用量越高,被kill的优先级越高;Burstable
,对使用量高于请求量的pod排序,占用越多,回收优先级越高;如果没有pod的使用超过请求,按照BestEffort策略回收;Guaranteed
,Guaranteed
pod 只有为所有的容器指定了要求和限制并且它们相等时才能得到保证。由于另一个 pod 的资源消耗,这些 pod 保证永远不会被驱逐。如果系统守护进程(例如 kubelet
、docker
、和 journald
)消耗的资源多于通过 system-reserved
或 kube-reserved
分配保留的资源,并且该节点只有 Guaranteed
或 Burstable
pod 使用少于剩余的请求,然后节点必须选择驱逐这样的 pod 以保持节点的稳定性并限制意外消耗对其他 pod 的影响。在这种情况下,它将首先驱逐优先级最低的 pod。有些情况下,可能只回收一小部分的资源就能使得Evication Signal
的值低于eviction thresholds
。但是,可能随着资源使用的波动或者新的调度Pod使得在该Node上很快又会触发evict pods的动作,eviction毕竟是耗时的动作,所以应该尽量避免这种情况的发生。
为了减少这类问题,每次Evict Pods后,Node上对应的Resource不仅要比Eviction Thresholds低,还要保证最少比Eviction Thresholds,再低--eviction-minimum-reclaim
中配置的数量。
例如使用下面的配置:
--eviction-hard=memory.available<500Mi,nodefs.available<1Gi,imagefs.available<100Gi
--eviction-minimum-reclaim="memory.available=0Mi,nodefs.available=500Mi,imagefs.available=2Gi"
如果 memory.available
驱逐阈值被触发,kubelet将保证 memory.available
至少为 500Mi
。对于 nodefs.available
,kubelet将保证 nodefs.available
至少为 1.5Gi
。对于 imagefs.available
,kubelet将保证 imagefs.available
至少为 102Gi
,直到不再有相关资源报告压力为止。
所有资源的默认 eviction-minimum-reclaim
值为 0。