现象

在 k8s 中创建 pod 时,突然出现如下情况

img

部署的 yaml 文件如下

yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-demo
namespace: tomcats
labels:
app: tomcat
spec:
replicas: 3
selector:
matchLabels:
app: tomcat
template:
metadata:
labels:
app: tomcat
spec:
nodeName: node1
containers:
- name: tomcat
image: tomcat:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080

分析

经过一番调查之后,大概理解如下

原因推测:

  • 节点资源告急,如内存和硬盘不够
  • containerd 配置出现问题或者冲突

治标:

  • 删除被驱逐的 pods: 通过 kubectl -n kube-system get pods | grep Evicted |awk '{print$1}'|xargs kubectl -n kube-system delete pods 命令,删除所有的被驱逐的 pod
  • 删除本次部署,kubectl
  • 换个富裕的节点部署

治本

  • 扩展节点空间,先看看节点缺什么.df -htop 命令分别看硬盘和内存.
  • 改变驱逐策略的限制,详见下面

关于驱逐策略:
源码 pkg/kubelet/apis/config/v1beta1/defaults_linux.go 给出了默认的硬驱逐配置:

  • memory.available < 100Mi
  • nodefs.available < 10%
  • nodefs.inodesFree < 5%
  • imagefs.available < 15%

其中:

nodefs.available<10%:容器 volume 使用的文件系统的可用空间, 包括文件系统剩余大小和 inode 数量
imagefs.available<15%:容器镜像使用的文件系统的可用空间, 包括文件系统剩余大小和 inode 数量
  • 当 imagefs 使用量达到阈值时,kubelet 会尝试删除不使用的镜像来清理磁盘空间.
  • 当 nodefs 使用量达到阈值时,kubelet 就会拒绝在该节点上运行新 Pod, 并向 API Server 注册一个 DiskPressure condition.
    • 然后 kubelet 会尝试删除死亡的 Pod 和容器来回收磁盘空间,如果此时 nodefs 使用量仍然没有低于阈值,kubelet 就会开始驱逐 Pod.
    • kubelet 驱逐 Pod 的过程中不会参考 Pod 的 QoS, 只是根据 Pod 的 nodefs 使用量来进行排名,并选取使用量最多的 Pod 进行驱逐。所以即使 QoS 等级为 Guaranteed 的 Pod 在这个阶段也有可能被驱逐.
    • 如果驱逐的是 Daemonset, kubelet 会阻止该 Pod 重启,直到 nodefs 可用量超过阈值.

详见 K8S 官网

  也就是说, 当硬盘剩余空间小于15%时, k8s会自动杀死pod, 尝试在其他节点上部署, 而我指定了noed1, 就会一直卡在创建->驱逐->创建...的循环

科学解法

最好的方法是扩容 , 直接解决忧愁.

还可以通过如下改变限制策略

硬阈值设置
将以下策略加入到 master 和 node 的 /etc/kubernetes/kubelet.env, 即 kublet 启动参数即可

plaintext
1
2
3
--eviction-hard=memory.available<256Mi,nodefs.available<1Gi,imagefs.available<1Gi \
--eviction-minimum-reclaim=memory.available=512Mi,nodefs.available=1Gi,imagefs.available=1Gi \
--eviction-pressure-transition-period=30s
第一行表示当memory<256Mi, nodefs<1G, imagesfs<1G, 时才会触发硬驱逐策略

第二行表示最小驱逐回收策略, 就是一旦驱逐策略被触发, 则要一直驱逐直到低于此行策略的阀值为止, 为了就是防止刚刚触发硬驱逐策略, 驱逐完之后没一会资源又涨上来了, 导致要反复驱逐的现象

第三行是为了防止node节点状态振荡

软阈值设置

plaintext
1
2
3
--eviction-soft=memory.available<10%,nodefs.available<15%,imagefs.available<15% \
--eviction-soft-grace-period=memory.available=2m,nodefs.available=2m,imagefs.available=2m \
--eviction-max-pod-grace-period=30
第一行表示软驱逐阀值, 使用百分比代替

第二行表示触发软驱逐后, 等待执行的时间, 若此时间内低于阀值, 则不再进行驱逐

第三行为pod宽限时间

修改驱逐阈值

/etc/kubernetes/manifests/kube-contoller-manager.yaml 添加:

--terminated-pod-gc-threshold=1

此值设定了Eviction pod最大的产生个数, 默认为12500, 最小改为1, 若为0, 则表示没有限制. 

最后,重启

systemctl restart kubelet

玄学解法

但是,实际上我做完这些操作之后都没有立刻起作用。却通过如下解决了…

  • 重启虚拟机
  • 让子弹飞一会儿… 过了 1 天他就自动好了

或许运维就是这样的玄学吧:😂:


参考文章:

CSDN:evicted 的出现原因
CSDN:k8s 资源分析
cnblog: 如何改变驱逐策略