案例現場:
測試環境集群本來正常,突然間歇性地出現服務不能正常訪問,過一會兒刷新頁面又可以正常訪問了.進入到服務所在的pod查看輸出日志並沒有發現異常.使用kubectl get node
命令正好發現一個節點是NotReady
狀態
為了方便觀察,使用kubectl get node --watch
來觀測一段時間,發現k8s-node1
節點不斷的在Ready和NotReady狀態之間切換(使用kubectl get node -o wide可以查看節點的ip信息).
進入到出現問題的節點,使用命令journalctl -f -u kubelet
來查看kubelet的日志信息,把錯誤日志截出來一段搜索一下,發現問題和這個問題基本上是一樣的,發現這個問題的時間和github上issue提出的時間是在同一天,也沒有看到解決辦法.但是基本能確定是因為集群中k8s-node1上的kubernetes版本不一致造成的(從上面截圖上可以看到,這個節點的版本是1.14.1其它的都是1.13.1,是怎么升上來的不清楚,可能是其它同事誤操作升級導致的)
搜索kubernetes NotReady
查看了一些解決經驗,很多都是重啟docker,重啟kubectl等,然后都解決不了問題.於是嘗試重置這個節點.
從集群中刪除Node
由於這個節點上運行着服務,直接刪除掉節點會導致服務不可用.我們首先使用kubectl drain
命令來驅逐這個節點上的所有pod
kubectl drain k8s-node1 --delete-local-data --force --ignore-daemonsets
以上命令中
--ignore-daemonsets
往往需要指定的,這是因為deamonset會忽略unschedulable
標簽(使用kubectl drain時會自動給節點打上不可調度標簽),因此deamonset控制器控制的pod被刪除后可能馬上又在此節點上啟動起來,這樣就會成為死循環.因此這里忽略daemonset.
實際在使用kubectl drain時候,命令行一直被阻塞,等了很久還在被阻塞.使用kubectl get pod命令查看pod狀態時.其中一個叫作
busybox
的pod一直處於Terminating
狀態. 使用kubectl delete pod busybox同樣無法刪除它.這時候可以使用命令kubectl delete pods busybox --grace-period=0 --force
來強制馬上刪除pod.
這時候控制台阻塞狀態結束.下面執行命令kubectl delete node k8s-node1
來刪除這個節點.然后我們重新安裝kubelet,kubeadm和kubectl
卸載舊版本
如果是通過yum方式安裝的,可以通過yum list installed|grep xxx
形式來找到已安裝的組件,然后刪除它們.刪除以后重新安裝.
這里之所以要重新安裝是因為版本升級成了較為新的版本,如果版本是一樣的,其它的不確定因素導致節點不穩定,又找不到具體原因,則可以通過
kubeadm reset
來重置安裝.
重置命令並不會重置設置的iptables規則和IPVS如果想要重置iptables,則需要執行以下命令:
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
如果想要重置IPVS,則需要執行以下命令:
ipvsadm -C
這里我能夠基本確定是由於版本不一致導致的,因此我並不重置iptables和IPVS,僅僅是重裝組件.
重新加入集群
重置完成以后,我們把刪除掉的k8s-node1節點使用kubeadm join
重新加入到集群中
如果忘記了主節點初始化時候生成的加入token,可以在主節點上執行
kubeadm token create --print-join-command
重新生成加入token,然后把生成的命令復制到要加入集群的節點上執行.
重新加入集群后,觀察了一段時間,一直是Ready狀態,感覺終於穩定了,但是同事又反饋部署服務時出現以下錯誤
Failed create pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox container "5159f7918d520aee74c5a08c8707f34b61bcf1c340bfc444125331034e1f57f6" network for pod "test-58f4789cb7-7nlk8": NetworkPlugin cni failed to set up pod "test-58f4789cb7-7nlk8_default" network: failed to set bridge addr: "cni0" already has an IP address different from 10.244.4.1/24
幸好有偉大的互聯網,通過搜索,找到以下解決方案
由於這次啟動以后初次部署pod就失敗了,因此此節點上還沒有運行的服務,我們不需要執行kubectl drain
,可以直接把這個節點刪除.然后執行以下命令
kubeadm reset
systemctl stop kubelet
systemctl stop docker
rm -rf /var/lib/cni/
rm -rf /var/lib/kubelet/*
rm -rf /etc/cni/
ifconfig cni0 down
ifconfig flannel.1 down
ifconfig docker0 down
ip link delete cni0
ip link delete flannel.1
systemctl start docker
完了以后重新加入集群.這次可以正常工作了.