工作负载异常:实例驱逐异常(Evicted)
驱逐原理
当节点出现异常时,为了保证工作负载的可用性,Kubernetes会通过驱逐机制(Eviction)将该节点上的Pod调离异常节点。
目前Kubernetes中存在两种Eviction机制,分别由kube-controller-manager和kubelet实现。
- kube-controller-manager实现的驱逐
kube-controller-manager主要由多个控制器构成,而驱逐的功能主要由node controller这个控制器实现,它会周期性检查所有节点状态,当节点处于NotReady状态超过一段时间后,驱逐该节点上所有Pod。
kube-controller-manager提供了以下启动参数控制驱逐:
- pod-eviction-timeout:即当节点宕机时间超过一定的时间间隔后,开始驱逐宕机节点上的Pod,默认为5min。
- node-eviction-rate:每秒需要排空的节点数量,默认为0.1,即每10s从一个节点驱逐Pod。
- secondary-node-eviction-rate:第二档的排空节点的速率。当集群中宕机节点过多时,排空节点的速率会降低至第二档,默认为0.01。
- unhealthy-zone-threshold:可用区的不健康阈值,默认为0.55,即当该可用区中节点宕机数目超过55%时,认为该可用区不健康。
- large-cluster-size-threshold:集群的大规模阈值,默认为50,当集群节点数量超过该阈值时认为集群属于大规模集群。大规模集群的可用区节点宕机数目超过55%时,则将排空节点速率降为0.01;假如是小规模集群,则将速率直接降为0,即停止驱逐节点上的Pod。
- kubelet的eviction机制
如果节点处于资源压力,那么kubelet就会执行驱逐策略。驱逐会考虑Pod的优先级,资源使用和资源申请。当优先级相同时,资源使用/资源申请最大的Pod会被首先驱逐。
kube-controller-manager的驱逐机制是粗粒度的,即驱逐一个节点上的所有Pod,而kubelet则是细粒度的,它驱逐的是节点上的某些Pod。此类驱逐会周期性检查本节点内存、磁盘等资源,当资源不足时,按照优先级驱逐部分Pod。关于Pod驱逐优先级,请参见kubelet驱逐时Pod的选择。
驱逐阈值分为软驱逐条件(Soft Eviction Thresholds)和硬驱逐条件(Hard Eviction Thresholds)两种机制,如下:
- 软驱逐条件:当节点的内存/磁盘空间达到一定的阈值后,kubelet不会马上回收资源,如果改善到低于阈值就不进行驱逐,若这段时间一直高于阈值就进行驱逐。
您可以通过以下参数配置软驱逐条件:
- eviction-soft:软驱逐阈值设置。当节点驱逐信号满足一定阈值时,例如memory.available<1.5Gi时,kubelet不会立即执行Pod驱逐,而会等待eviction-soft-grace-period时间,假如该时间过后,依然还是达到了软驱逐阈值,则触发一次Pod驱逐。
- eviction-soft-grace-period:当达到软驱逐阈值时,允许Pod优雅终止的时间,即软驱逐宽限期,软驱逐信号与驱逐处理之间的时间差。默认为90秒。
- eviction-max-pod-grace-period:最大驱逐pod宽限期,停止信号与kill之间的时间差。
- 硬驱逐条件:硬驱逐机制则简单的多,一旦达到阈值,直接把Pod从本地驱逐。
您可以通过以下参数配置硬驱逐条件:
eviction-hard:硬驱逐阈值设置。当节点驱逐信号满足一定阈值时,例如memory.available<1Gi,即当节点可用内存低于1Gi时,会立即触发一次Pod驱逐。
kubelet 具有以下默认硬驱逐条件:
- memory.available<100Mi
- nodefs.available<10%
- imagefs.available<15%
- nodefs.inodesFree<5%(Linux 节点)
除此之外,kubelet还提供了其他的驱逐参数:
- eviction-pressure-transition-period:驱逐等待时间。当出现节点压力驱逐时,节点需要等待一定的时间,才会被设置为DiskPressure或者MemoryPressure,然后开启Pod驱逐,该时间默认为5分钟。该参数可以防止在某些情况下,节点在软驱逐条件上下振荡而出现错误的驱逐决策。
- eviction-minimum-reclaim:表示每一次驱逐必须至少回收多少资源。该参数可以避免在某些情况下,驱逐Pod只会回收少量的资源,导致kubelet反复触发多次驱逐。
- 软驱逐条件:当节点的内存/磁盘空间达到一定的阈值后,kubelet不会马上回收资源,如果改善到低于阈值就不进行驱逐,若这段时间一直高于阈值就进行驱逐。
问题定位
若节点故障时,实例未被驱逐,请先按照如下方法进行问题定位。
使用如下命令发现很多pod的状态为Evicted:
kubectl get pods
cat /var/log/cce/kubernetes/kubelet.log | grep -i Evicted -C3
排查思路
以下排查思路根据原因的出现概率进行排序,建议您从高频率原因往低频率原因排查,从而帮助您快速找到问题的原因。
如果解决完某个可能原因仍未解决问题,请继续排查其他可能原因。
排查项一:节点是否存在资源压力
当满足硬性或软性驱逐条件时,即存在资源压力时,kubelet会根据驱逐信号将节点设置为相应的节点状况,并为节点打上对应的污点。请通过以下步骤查看节点是否存在对应的污点。
$ kubectl describe node 192.168.0.37 Name: 192.168.0.37 ... Taints: key1=value1:NoSchedule ...
节点状况 |
节点污点 |
驱逐信号 |
描述 |
---|---|---|---|
MemoryPressure |
node.kubernetes.io/memory-pressure |
memory.available |
节点上的可用内存已满足驱逐条件。 |
DiskPressure |
node.kubernetes.io/disk-pressure |
nodefs.available、nodefs.inodesFree、imagefs.available 或 imagefs.inodesFree |
节点的根文件系统或镜像文件系统上的可用磁盘空间和 inode 已满足驱逐条件。 |
PIDPressure |
node.kubernetes.io/pid-pressure |
pid.available |
节点上的可用进程标识符已低于驱逐条件。 |
排查项三:是否满足停止驱逐实例的条件
若属于小规格的集群(集群节点数小于50个节点),如果故障的节点大于总节点数的55%,实例的驱逐将会被暂停。此情况下Kubernetes将不再尝试驱逐故障节点的工作负载,具体请参见节点驱逐速率限制。
排查项四:容器与节点上的“资源分配量”是否一致
容器被驱逐后还会频繁调度到原节点。
问题原因:
节点驱逐容器是根据节点的“资源使用率”进行判断;容器的调度规则是根据节点上的“资源分配量”进行判断。由于判断标准不同,所以可能会出现被驱逐后又再次被调度到原节点的情况。
解决方案:
遇到此类问题时,请合理分配各容器的资源分配量即可解决。
排查项五:工作负载实例不断失败并重新部署
工作负载实例出现不断失败,不断重新部署的情况。
问题分析:
pod驱逐后,如果新调度到的节点也有驱逐情况,就会再次被驱逐;甚至出现pod不断被驱逐的情况。
如果是由kube-controller-manager触发的驱逐,会留下一个状态为Terminating的pod;直到容器所在节点状态恢复后,pod才会自动删除。如果节点已经删除或者其他原因导致的无法恢复,可以使用“强制删除”删除pod。
如果是由kubelet触发的驱逐,会留下一个状态为Evicted的pod,此pod只是方便后期定位的记录,可以直接删除。
解决方案:
使用如下命令删除旧驱赶的遗留:
kubectl get pods <namespace> | grep Evicted | awk '{print $1}' | xargs kubectl delete pod <namespace>
<namespace>为命名空间名称,请根据需要指定。