記一則K8S Node NotReady故障
報(bào)障:
今日上午,值班同學(xué)發(fā)現(xiàn)airflow無法使用。查看時(shí)其部署的Node節(jié)點(diǎn)NotReady了。
分析:
馬上查看K8S集群節(jié)點(diǎn)的狀態(tài),發(fā)現(xiàn)這個(gè)節(jié)點(diǎn)已經(jīng)是NotReady狀態(tài)了。第一反應(yīng)就是ping下節(jié)點(diǎn)看是否宕機(jī)了?ping正常,于是登錄到該節(jié)點(diǎn)查看kubelet狀態(tài)。發(fā)現(xiàn)kubelet報(bào)runtime不可用,查看containerd的狀態(tài),一直在不斷的重啟,而且啟動(dòng)不成功。為了盡快恢復(fù)業(yè)務(wù),決定先將containerd的數(shù)據(jù)目錄清空后重新拉起。于是刪除containerd數(shù)據(jù)目錄下的文件夾:
# ls -lrth /xpu-k8s-data/containerd/
total 0
drwx------ 2 root root 6 Apr 28 10:54 io.containerd.snapshotter.v1.btrfs
drwx------ 3 root root 31 Apr 28 10:54 io.containerd.snapshotter.v1.aufs
drwx------ 3 root root 31 Apr 28 10:54 io.containerd.snapshotter.v1.native
drwx--x--x 2 root root 29 Apr 28 10:54 io.containerd.metadata.v1.bolt
drwx--x--x 2 root root 6 Apr 28 10:54 io.containerd.runtime.v1.linux
drwxr-xr-x 4 root root 45 Apr 28 10:54 io.containerd.content.v1.content
drwx------ 3 root root 54 Apr 28 10:54 io.containerd.snapshotter.v1.overlayfs
drwx--x--x 3 root root 28 Apr 28 10:54 io.containerd.runtime.v2.task
drwxr-xr-x 4 root root 53 Apr 28 10:55 io.containerd.grpc.v1.cri
drwx------ 2 root root 6 Apr 28 14:49 tmpmounts
# rm -rf /xpu-k8s-data/containerd/*
發(fā)現(xiàn)執(zhí)行的時(shí)間很長(zhǎng),超過幾分鐘。通過du命令統(tǒng)計(jì)該目錄的大小也很久,我判斷是這個(gè)目錄下的小文件太多了。于是我ctrl+c掉rm和du命令。直接將該目錄改個(gè)名字后重新創(chuàng)建一個(gè)目錄。然后重新拉起containerd和kubelet進(jìn)程后節(jié)點(diǎn)Ready了。pod也正常了。
然后接著再來刪除之前的數(shù)據(jù)目錄,執(zhí)行刪除后經(jīng)過30min-60min才刪除完成。通過rm -rfv 參數(shù)可以看到打印出來刪除的文件信息,是pod中存在大量的python,go的.cache和.git的小文件。查看containerd的報(bào)錯(cuò):
猜測(cè)是因?yàn)樾∥募?shù)量過多,導(dǎo)致節(jié)點(diǎn)containerd停止后重啟失敗,不斷重啟導(dǎo)致節(jié)點(diǎn)NotReady的。
恢復(fù)一段時(shí)間后,airflow跑任務(wù)時(shí),拉起個(gè)別的pod沒有問題,但是當(dāng)同時(shí)拉起幾十個(gè)pod跑任務(wù)的時(shí)候有很多的pod無法啟動(dòng)。報(bào)如下錯(cuò)誤:
該節(jié)點(diǎn)的pod網(wǎng)段IP地址已經(jīng)用完,無法分配IP了。集群設(shè)計(jì)的時(shí)候給每個(gè)Node的子網(wǎng)掩碼是25??梢圆渴?25個(gè)pod。但是現(xiàn)在節(jié)點(diǎn)上的pod才十幾個(gè)。猜測(cè)是之前節(jié)點(diǎn)故障的時(shí)候,直接刪除了元數(shù)據(jù)后拉起containerd導(dǎo)致原來的pod在系統(tǒng)上的網(wǎng)絡(luò)信息沒有被刪除。導(dǎo)致IP被占用了。我們的集群采用了flannel組件,并且開啟了--kube-subnet-mgr參數(shù)。所以IP分配信息不會(huì)記錄到etcd,而是直接記錄到Node節(jié)點(diǎn)上的。
# ps -ef | grep flannel
root 6450 45116 0 14:59 pts/4 00:00:00 grep --color=auto flannel
root 53065 52700 0 13:02 ? 00:00:43 /opt/bin/flanneld --ip-masq --kube-subnet-mgr
Pod在Node上的網(wǎng)絡(luò)信息主要有兩點(diǎn):
1)容器在Node側(cè)的vethxxx接口;
2)容器在Node側(cè)的IP地址;
所以,只要我們刪除舊Pod的容器殘留在Node上的以上網(wǎng)絡(luò)信息應(yīng)該就可以恢復(fù)了。
解決:
1)找到容器在Node側(cè)的vethxxx接口并刪除
我們知道,veth對(duì)一側(cè)在容器里面,一側(cè)在Node側(cè)。通過命令ip addr可以查看到。這里我們需要找到不存在容器遺留在Node的vethxxx接口。
如上圖所示,每個(gè)vethxxx接口都有一個(gè)Node側(cè)的index ID(第一列數(shù)字),而vethxxx@if后面的數(shù)字3是該veth接口對(duì)應(yīng)在容器側(cè)的eth0網(wǎng)卡在容器內(nèi)的index ID。容器和Node的veth接口對(duì)應(yīng)關(guān)系如下:
通過這樣的方式找到其映射關(guān)系的。有了這個(gè)信息之后,我就可以去到該Node上所有的容器中拿到eth0對(duì)應(yīng)的在Node的index ID,從而在Node側(cè)過濾找出已經(jīng)無效的vethxxx接口并刪掉。操作如下:
for pid in $(for i in $(crictl ps | awk '{print $1}'); do crictl inspect $i | grep -i pid|grep , | awk '{print $2}' | sed 's/,//';done);do nsenter -t $pid --net ;done
由于Node上現(xiàn)有的容器不多,十幾個(gè)所以通過這種方式逐一登錄拿到對(duì)應(yīng)的index ID。如果容器較多,需要結(jié)合expect工具做自動(dòng)識(shí)別處理。這里沒有做。拿到所有有效的veth的index ID后報(bào)錯(cuò)到veth_yes文件中,把Node側(cè)所有的veth信息報(bào)錯(cuò)到veth_all文件中:
ip add | grep veth > veth_all
然后根據(jù)有效的index ID把其信息從veth_all中刪除,得到所有要?jiǎng)h除的vethxxx接口信息并刪除:
// 刪除有效的veth信息
#!/bin/bash
for i in $(cat veth_yes)
do
grep $i veth_all; sed -i "/$i/d" veth_all
done
// 刪除所有無效的vethxxx接口信息
#!/bin/bash
for i in $(cat veth_all | awk '{print $2}' | awk -F@ '{print $1}')
do
ip link delete $i
done
刪除后,Node側(cè)只剩下當(dāng)前running容器的vethxxx接口了。
2)找到容器在Node側(cè)記錄的IP地址并刪除
veth接口處理完,那么IP地址沒有釋放該如何處理呢?
查閱資料后得知,IPAM插件已分配的IP地址保存在/var/lib/cni/networks/cbr0文件中。如下:
于是,將其中未真正在使用的IP地址文件刪除即可。刪除后如下:
此時(shí),所有無法分配IP的Pod都可以正常獲取IP從creating狀態(tài)變?yōu)镽unning狀態(tài)了。
至此,問題修復(fù)!略略略略略~~~