又一次偷偷化解了可能發生的重大事故。不想看過程的可以直接跳到末尾看處理方案。
一個網絡錯誤
某天,上kplcloud構建一個測試應用,構建完成之後發現新pod一直啟動失敗,並且拋出了以下錯誤信息:
Failed create pod sandbox: rpc error: code = Unknown desc = NetworkPlugin cni failed to set up pod "xxxxxx-fc4cb949f-gpkm2_xxxxxxx" network: netplugin failed but error parsing its diagnostic message "": unexpected end of JSON input
會k8s的運維同學早已不在,突然出問題了怎麼辦?
試著開始解決問題。
一、有沒有可能是鏡像拉取失敗,開始找問題:
- 登錄集群所有服務器查看空間是否佔滿(然而並沒有佔滿)
- 查詢集群所有服務器網絡情況(也沒有問題)
- 再啟一個pod試試?(起不來)
這就尷尬了......,有沒有可能是calico的問題?
二、查看服務器報錯信息
嘗試以下命令看服務器的報錯信息:
$ journalctl -exf
確實有一些錯誤信息:
這個錯誤太廣泛了,繼續嘗試從其他地方找找問題。
此時已經開始在思考如何跑路的問題了...
要不嘗試從重啟能否解決?
風險太大,不能冒險。雖然很多時候重啟能解決大部分問題,但重啟docker、k8s在這種情況下不是最佳選擇。
繼續搜刮日誌,猜測是無法分配IP的問題,那目標轉向calico
從calico-node上面找問題
查詢ip池是否用完。
使用calicoamd命令查詢calico是否正常正常運行
$ calicoctl get ippools -o wide
CIDR NAT IPIP
172.20.0.0/16 true false
$ calicoctl node status
似乎是沒啥問題。
開始場外求助......
無果
既然calico-node都運行正常,應該不會是calico-etcd的問題吧。
試試calico-etcd
本著有疑問就查證試試的態度,下面開始對calico-etcd進行一頓騷操作。
為了減少代碼量方便閱讀,以下etcdctl所需要加的證書及endpoints,就不一一添加了,大家參考一下就好:
ETCDCTL_API=3 etcdctl --cacert=/etc/etcd/ssl/ca.pem \
--cert=/etc/etcd/ssl/etcd.pem \
--key=/etc/etcd/ssl/etcd-key.pem \
--endpoints=http://10.xx.xx.1:2379,http://10.xx.xx.2:2379,http://10.xx.xx.3:2379
calico並沒有問題,試試calico 所使用的 ETCD是否正常,進入calico-etcd集群:
$ ETCDCTL_API=3 etcdctl member list
bde98346d77cfa1: name=node-1 peerURLs=http://10.xx.xx.1:2380 clientURLs=http://10.xx.xx.1:2379 isLeader=true
299fcfbf514069ed: name=node-2 peerURLs=http://10.xx.xx.2:2380 clientURLs=http://10.xx.xx.2:2379 isLeader=false
954e5cdb2d25c491: name=node-3 peerURLs=http://10.xx.xx.3:2380 clientURLs=http://10.xx.xx.3:2379 isLeader=false
似乎集群也運行正常,get數據也正常。
一切看起來都感覺是多麼的正常,似乎沒有什麼毛病。
算了,算了,還是先寫會簡歷吧,換換腦子。
那嘗試向ETCD寫入一條數據試試?
$ ETCDCTL_API=3 etcdctl put /hello world
Error: etcdserver: mvcc: database space exceeded
報了一個錯Error: etcdserver: mvcc: database space exceeded???
似乎是找到原因了,既然定位到問題所在,那接下來就好辦了。(不用跑路了(⁎⁍̴̛ᴗ⁍̴̛⁎))把簡歷先放一放。
感謝偉大的google,我從etcd官網找到了一些線索及解決方案,後面我貼上官網介紹,先解決問題:
使用etcdctl endpoint status
查詢etcd各個節點的使用狀態:
$ ETCDCTL_API=3 etcdctl endpoint status
http://10.xx.xx.1:2379, 299fcfbf514069ed, 3.2.18, 2.1 GB, false, 7, 8701663
http://10.xx.xx.2:2379, bde98346d77cfa1, 3.2.18, 2.1 GB, true, 7, 8701683
http://10.xx.xx.3:2379, 954e5cdb2d25c491, 3.2.18, 2.1 GB, false, 7, 8701687
上面可以看到集群空間已經使用了2.1GB了,這個值需要留意一下。
查詢etcd是否有告警信息使用命令etcdctl alarm list
:
$ ETCDCTL_API=3 etcdctl alarm list
memberID:2999344297460918765 alarm:NOSPACE
顯示了一個alerm:NOSPACE
,這個表示沒空間了,那是沒什麼空間呢?磁盤還是內存?先查詢一下。
似乎磁盤、內存空間都足夠的。從官網的信息瞭解到應該是etcd配額的問題,Etcd v3 的默認的 backend quota 2GB,也就是說etcd默認最大的配額是2GB,如果超過了則無法再寫入數據,要麼把舊數據刪除,要麼把數據壓縮了。
參考官方的解決方案
ETCD官網參考:https://etcd.io/docs/v3.2.17/op-guide/maintenance/
-
獲取etcd的舊版本號
$ ETCDCTL_API=3 etcdctl endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9].*' 5395771 5395771 5395771
-
壓縮舊版本
$ ETCDCTL_API=3 etcdctl compact 5395771 compacted revision 5395771
-
整理碎片
$ ETCDCTL_API=3 etcdctl defrag Finished defragmenting etcd member[http://10.xx.xx.1:2379] Finished defragmenting etcd member[http://10.xx.xx.2:2379] Finished defragmenting etcd member[http://10.xx.xx.3:2379]
-
關閉告警
$ ETCDCTL_API=3 etcdctl alarm disarm memberID:2999344297460918765 alarm:NOSPACE $ ETCDCTL_API=3 etcdctl alarm list
-
測試數據是否可寫入
$ ETCDCTL_API=3 etcdctl put /hello world OK $ ETCDCTL_API=3 etcdctl get /hello OK
回到k8s這邊,刪除那個失敗的pod,並查看是否可正常分配ip。
一切正確,完美。
為了避免後續再出現類似問題,需要設置自動壓縮,啟動自動壓縮功能需要在etcd啟動參考上加上xxxxx=1
https://skyao.gitbooks.io/learning-etcd3/content/documentation/op-guide/maintenance.html
etcd 默認不會自動 compact,需要設置啟動參數,或者通過命令進行compact,如果變更頻繁建議設置,否則會導致空間和內存的浪費以及錯誤。Etcd v3 的默認的 backend quota 2GB,如果不 compact,boltdb 文件大小超過這個限制後,就會報錯:
”Error: etcdserver: mvcc: database space exceeded”
,導致數據無法寫入。
產生這麼多垃圾數據的原因就是因為頻繁的調度,我們集群有大量CronJob在執行,並且執行的非常活躍,每次產生新的Pod都會被分配到ip。有可能是因為pod時間太短或沒有及時註銷而導致calico-etcd產生了大量垃圾數據。
尾巴
因calico-etcd集群的的使用配額滿了,在創建pod時calico所分配的IP無法寫入到etcd裡,從而導致pod創建失敗也就無法註冊到CoreDNS了。
為了不採坑,監控是非常重要的,我們有etcd集群的監控,卻忽略了etcd配額的監控,幸運的是當時並沒有應用重啟動或升級,沒有造成損失。
最後的建議就是,沒事上去點點,說不定會有您意想不到的驚喜(驚嚇)。
作者:宜信技術學院 王聰