vmware 搭建k8s无法ping通子节点_一波四折 —— 记一次K8S集群应用故障排查
一個周四的下午,客戶的報障打破了微信群的平靜。
“我們部署在自建K8S集群上的應用突然無法正常訪問了,現在業務受到了影響!”
收到客戶的報障,我們立刻響應,向客戶了解了問題現象和具體報錯信息。
客戶反饋K8S集群部署在云主機上,K8S的應用pod example-app通過訪問外部域名example-api.com調用接口,同時訪問云數據庫做數據查詢后將結果返回客戶端??蛻襞挪閼胮od日志,日志中有如下報錯:
可以看到最關鍵的信息是Name or service not known。該報錯一般為域名無法解析導致的。
由于客戶的應用pod只訪問example-api.com這一個外部域名,因此判斷應該是pod解析該域名時出現異常。為了進一步驗證,我們執行kubectl exec -it example-app /bin/sh命令進入pod內執行ping example-api.com命令,果然出現了相同的報錯。
因此可以確認應用日志中的報錯是域名解析失敗導致的。
執行kubectl get pod example-app -o yaml|grep dnsPolicy查看pod的dns策略,是ClusterFirst模式,也就是pod使用K8S集群的kube-dns服務做域名解析。
執行命令kubectl get svc kube-dns -n kube-system,確認kube-dns服務的clusterIP是192.168.0.10 查看pod內的/etc/resolv.conf文件,nameserver設置的正是該IP。再執行kubectl describe svc kube-dns -n kube-system|grep Endpoints,可以看到dns服務關聯了一個coredns pod作為后端。
執行kubectl get pods -n kube-system|grep coredns看到kube-dns關聯的coredns pod處于running狀態。
再執行kubectl logs coredns –n kube-system,看到pod日志中有大量和客戶配置的外部dns服務器IP地址通訊超時的報錯。
10.16.16.16和172.16.16.16為客戶自建DNS服務器的IP地址
。為了確認是否是DNS服務器有問題,我們在example-app pod中分別執行nslookup example-api.com 10.16.16.16和nslookup example-api.com 172.16.16.16,均能解析出正確的IP地址。
因此判斷問題應該出在coredns pod上。此時我們發現,coredns pod的狀態變成了crashloobbackoff,稍后又變成了running。
觀察一段時間后發現pod在這兩個狀態之間反復切換。鑒于整個集群只有一個coredns pod,我們修改了coredns的deploy,將pod副本數調至2,新擴的pod一直處于running狀態,pod日志中也沒有出現和10.16.16.16、172.16.16.16的通信超時的報錯。而此時example-app pod也可以正常解析域名了!可以確認之前是集群唯一的coredns pod狀態異常導致集群DNS服務不可用。
那么coredns pod為什么會出現異常呢?
再次查看異常的pod日志,發現除了和外部DNS服務器有通訊超時的記錄,還有和集群api-server通訊超時的記錄。因此有必要懷疑是pod所處的網絡有問題。在客戶的K8S集群網絡規劃中,pod使用和集群node不同的子網通訊。通過在K8S節點云主機上綁定pod子網的彈性網卡,在網卡上給節點的pod在pod子網中分配IP,實現pod的網絡可達。
由于example-app pod是可以與外部通訊的,因此pod子網層面是沒有問題的。我們將焦點移至coredns pod使用的彈性網卡上。彈性網卡在節點云主機操作系統中的設備名是eth1,pod子網網關是10.176.96.1在節點上執行ping -I eth1 10.176.96.1,結果如圖:
可見云主機無法通過eth1 ping通子網網關,而且找不到eth1設備。執行ifconfig命令發現eth1設備沒有被系統識別到。而彈性網卡底層是被正常掛載到云主機上的。
手動執行echo 1 > /sys/bus/pci/rescan命令重新掃描彈性網卡,發現eth1出現了,此時執行ping -I eth1 10.176.96.1也可以ping通了!而異常的coredns pod也恢復了正常。判斷之前應該是系統異常導致的網卡沒有被識別到導致。
通過這一問題也提醒我們如果集群需要使用kube-dns服務,coredns的pod一定要配置多副本,以免單個pod異常導致集群DNS不可用。
Part2?一波剛平一波又起域名解析的問題解決,本以為已經結案,誰知新的問題接踵而來。客戶調用應用,不再報錯域名解析失敗。但是仍然不能正常返回結果。排查應用日志,報錯如下:
通過報錯判斷是應用pod連接云數據庫超時導致。排查云數據庫所在子網的路由、ACL和白名單設置,均無異常。連接pod后可以ping通數據庫域名,判斷pod與數據庫的網絡鏈路是正常的。但是pod內無法telnet通數據庫域名的3306端口,判斷這就是導致連接數據庫超時的原因了!
排查pod內的防火墻,沒有開啟。pod所在的子網ACL,沒有限制。表面的分析沒有任何線索,于是只能祭出網絡問題排查的經典手段——tcpdump抓包!
由于pod內的容器一般CPU、內存、網絡資源和存儲空間有限,在pod內抓包會占用大量資源和存儲空間,抓包結束后數據包取出也比較繁瑣。而且有的容器鏡像是無法安裝tcpdump工具的。所以通常我們不會在容器內抓包。
基于K8S集群的網絡架構,pod的網絡通訊是通過所在節點云主機的輔助彈性網卡收發數據的。因此我們只要在pod所在節點云主機上對相應的網卡進行抓包即可。
在客戶的場景下,應用pod使用所在節點的eth1網卡,所以pod telnet云數據庫的3306端口時,我們直接在節點上抓取eth1網卡上與云數據庫IP交互的數據包即可。
pod的IP是10.176.98.29,云數據庫的IP是10.176.46.4。在pod的容器內執行telnet 10.176.46.4 3306,同時在節點上執行tcpdump -i eth1 host 10.176.46.4 -w /tmp/mysql.cap。pod內telnet超時后,我們結束抓包,將cap文件取出后發現居然一片空白,一個包都沒有抓到!
這不科學!
之前pod內可以ping通云數據庫,說明一定有數據包從pod所在云主機發出并收到了回包。為了驗證pod telnet請求的包是否正常發出,我們干脆不把抓包范圍局限在eth1網卡,而是使用tcpdump -i any host 10.176.46.4 -w /tmp/mysql.cap對云主機所有網絡接口抓包。這次終于抓到了數據包,發現telnet發出后,沒有收到數據庫的任何回包。
在telnet的同時,集群中有其他pod可以正常連接云數據庫,所以因為云數據庫側異常導致沒有回包的可能性不大。云主機可以和外界通訊的網卡只有eth0和eth1,莫非……為了驗證我們的猜想,在telnet時,節點上執行tcpdump -i eth0 host 10.176.46.4,果然看到了pod發出的到云數據庫的數據包!
所以pod 容器telnet不通云數據庫3306端口的原因也真相大白了。因為pod telnet云數據庫的數據包沒有走eth1,而是走了eth0,數據包發送至云數據庫后,云數據庫的回包發給了pod的子網網關。
SDN網絡OVS判斷來包是從node子網網關發出(eth0),而回包卻是發往pod子網(eth1)源和目的地址不一致,因此將數據包丟棄。pod也就無法收到數據庫的回包了。之前可以ping通是因為ICMP協議是代答的,即使源和目的地址不一致,也可以正常收到回包。
那么,pod的所有網絡請求正常是應該通過云主機上的輔助網卡收發的,為什么走了云主機主網卡了呢?正常的K8S集群節點上配置了table 2路由規則,定義了pod的網絡請求默認路由的下一跳是pod子網網關,并且走輔助網卡,如下圖所示:
而在客戶的應用pod所在節點執行ip r show table 2,我們看到的結果和第一次抓包一樣,空空如也。。。
路由是由K8S集群的網絡插件維護,路由缺失問題在網絡插件日志中沒有發現任何線索,具體原因不得而知。當務之急是修復問題。
可以通過重啟ipamd容器恢復table 2路由。
執行docker ps | grep ipamd | grep sh找到ipamd的容器ID。
然后執行docker restart 容器ID重啟容器。
再次執行ip r show table 2,終于看到了路由規則!
Finally,此時在應用pod內測試可以telnet通云數據庫的3306端口??蛻舻膽谜{用也終于可以成功返回結果。
然鵝,如果各位看官覺得這個case到這里就結束了,那就和當時排障的攻城獅一樣圖樣圖森破了。
Part3慢=不可用
就在攻城獅以為一切都恢復正常時,客戶的追加反饋表明這個問題只是進入了下一個階段。
客戶反饋應用雖然可以正常調用,但是一次調用要超過一分鐘才能有返回結果,之前正常的速度是僅需幾秒就可以返回結果。現在這樣的速度完全不能滿足業務要求,相當于還是不可用的。
問題尚未解決,攻城獅仍需努力!
分析應用調用返回慢的問題,一是著眼于應用流程的各個環節,如客戶端,服務端對業務請求的處理時間,另外一個就是排查數據傳輸鏈路是否有延遲。在客戶的場景下,就是確認pod和云數據庫在處理請求上是否有瓶頸,還有就是pod到云數據庫之間的網絡傳輸是否有延遲。在pod內ping云數據庫IP,沒有超時丟包,延遲很低。
要想確認pod和云數據庫在處理請求時的時長,還是要依靠tcpdump工具抓包分析。于是我們在pod對數據庫發起一次完整的請求過程中,依然使用tcpdump -i eth1 host 10.176.46.4 -w /tmp/mysql.cap命令在pod所在節點抓包。將數據包取出后分析發現,一次完整的業務請求,pod會對數據庫做13次查詢。對比第一次查詢和最后一次查詢的時間,如圖所示:
可以發現13次請求用了1分鐘左右,與業務調用耗時吻合。排查云數據庫監控,發現內存
使用接近100%
同時實例慢查詢日志中有大量慢sql記錄,可以看到幾乎每次查詢都耗時較長
可見如果業務調用的13次請求,每次都是慢查詢,耗時4秒左右,就會導致我們看到的完整請求耗時一分鐘左右。
因此判斷瓶頸應該主要在云數據庫上,建議客戶對數據庫慢查詢進行優化,降低內存負載。然后觀察應用調用時長是否恢復正常。
part4 問題的真相只有一個!
當我們天真地以為優化完數據庫慢查詢后,一切就都塵埃落定時??蛻舻姆答亷缀踝屓吮罎ⅰ獌灮樵兒?#xff0c;數據庫內存使用已降至30%,慢日志中也幾乎沒有慢sql記錄。而應用的調用時長仍然沒有縮短!
一定還有哪個環節有疏漏。
為了完整了解應用pod在應用調用過程中都產生了哪些數據交互,我們決定再次抓包分析,但焦點不再集中在云數據庫上,而是以pod維度進行抓包。使用tcpdump -i eth1 host -w /tmp/app.cap命令在pod所在節點抓取所有和pod相關的包,分析數據包后果然有了新的發現:pod與100.64.249.132這個地址有文件傳輸交互。
查看數據包詳細數據發現這個地址是OSS對象存儲解析到的域名!pod還會與oss傳輸文件這個重要環節在此前是不知道的,客戶也沒有主動告知。
這也提醒我們在分析應用問題時,務必要搞清完整的業務調用流程,應用架構和涉及到的產品環節,否則擠牙膏似的信息輸出和被問題現象牽著鼻子走,會浪費大量時間,甚至嚴重阻礙問題排查。
我們在pod內測試ping 100.64.249.132,延時非常感人。
與客戶確認,客戶反饋OSS域名解析的IP貌似不對。在業務架構規劃時,為了保證客戶pod與oss的網絡性能,配置了通過專線連接oss。當前解析的IP沒有走專線網段,而是走了普通的網段,無法滿足性能要求。正常走專線的域名解析IP應該是10.219.226.2。
但是域名解析為什么會出現問題呢?
各位童鞋是否還記得part1中我們提到客戶的pod使用的是kube-dns提供的dns解析,而kube-dns配置的上游服務器是客戶自建的dns服務器?經過客戶測試發現,自建dns服務器對oss域名的解析就是100.64.249.132。應該是近期客戶側維護dns服務器的時候誤操作修改了解析導致的。。。將自建dns服務器的域名解析地址修改回正確地址后。再次在pod內測試,結果如下:
再次測試應用調用,終于恢復到了正常的時長!可喜可賀!
?至此客戶的問題卍解,總結問題排查過程,有幾點值得分享:
1、? k8s集群如果使用kube-dns服務,coredns pod務必配置多副本,避免單點故障導致集群dns服務不可用。
2、? 排查K8S集群pod網絡問題時,可以在pod所在節點抓取pod使用的輔助網卡的相應網絡數據包,避免直接在pod內抓包。
3、? 應用系統性能排查涉及到各個節點設備和網絡傳輸,務必了解清楚完整的系統架構,調用流程,再針對涉及的每個環節逐一分析。
以上就是一次“波折”的K8S應用問題排查過程,感謝各位童鞋閱讀,如果能夠對大家有所幫助,歡迎點贊轉發評論。關注我們的公眾號,更多精彩內容會持續放送!
總結
以上是生活随笔為你收集整理的vmware 搭建k8s无法ping通子节点_一波四折 —— 记一次K8S集群应用故障排查的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java大牛的一些总结,献给对未来还在迷
- 下一篇: 六本JAVA架构书,构建科学得架构知识体