當前位置:
首頁 > 最新 > Kubernetes服務發現與故障排除

Kubernetes服務發現與故障排除

本文為Kubernetes監控系列的第二篇文章,系列目錄如下:

本文是關於在生產中使用Kubernetes系列的一部分。第一部分介紹了Kubernetes和監控工具的基礎知識;第二部分涵蓋了Kubernetes報警的最佳實踐;這部分將介紹對Kubernetes故障排除,特別是服務發現,最後一部分是監控Kubernetes的實際使用案例。像Kubernetes,DC / OS Mesos或Docker Swarm這樣的容器編排平台可以幫助你方便地管理容器,但對解決容器問題並沒有什麼幫助:

它們是孤立的,你和你要監視的進程之間存在一定的障礙,在主機上運行的傳統故障排除工具不了解容器、命名空間和編排平台。

它們帶來最小的運行時間,只需要服務及其依賴項,而不需要所有的故障排除工具,想像下只用busybox來進行故障排除!

它們調度在你集群、進行容器移動,擴容或者縮容。隨著流程的結束,它們變得非常不穩定,出現並消失。

並通過新的虛擬網路層互相通信。

本文將通過一個真實用例講訴如何在Kubernetes中進行故障排除。我們將涵蓋Kubernetes內部3個不同層的故障排除:

第一部分:Kubernetes故障排除之服務發現

第二部分:Kubernetes故障排除之DNS解析

第三部分:Kubernetes故障排除之使用Docker運行容器

本文場景將使用一個簡單的Kubernetes服務[1],包括3個Nginx pod和一個帶有curl命令的客戶端。在鏈接中可以看到場景需要使用的yaml文件 backend.yaml。如果你剛剛接觸Kubernetes,可以看下「Understanding how Kubernetes DNS services work[2]」這篇文章來學習如何部署上述服務。實際操作如下:

然後創建一個客戶端來載入我們的後端服務:

Kubernetes故障排除之服務發現

在client容器的shell端運行:root@client:/# curl backend.critical-app.svc.cluster.local,不過這次curl命令卡住了10秒,然後返回了預期網址!作為一個分散式系統工程師,這是最糟糕的事情之一:你希望直接失敗或者成功,而不是等待10秒。

為了定位出問題,我們使用了Sysdig。Sysdig是一個開源Linux可視化工具,提供對容器的本地可見性,包括Docker、Kubernetes、DC / OS和Mesos等等。將htop,tcpdump,strace,lsof,netstat等的功能組合在一起,Sysdig提供了Kubernetes基礎架構環境中的所有系統調用和應用程序數據。Monitoring Kubernetes with Sysdig[4]中很好地介紹了如何在Kubernetes中使用這個工具。

為了分析上述問題原因,我們將請求sysdig來dump所有信息到捕獲文件中:

快速解釋下每個參數:

-k http://localhost:8080 連接Kubernetes API

-s8192 擴大IO緩衝區,因為我們需要顯示全部內容,否則默認情況下會被切斷,

-zw capture.scap 將系統調用與元數據信息壓縮並dump到文件中

同時,我們將再次運行curl命令來複現這個問題:# curl backend.critical-app.svc.cluster.local。這確保了我們在上面捕獲的文件中擁有所有數據,以重現場景並解決問題。

一旦curl返回,我們可以執行Ctrl+C來終止數據捕獲,並且我們將擁有一個10s的捕獲文件,包括我們的Kubernetes主機中發生的所有事情以及服務發現過程。現在我們可以開始在集群內或集群外解決問題,只要在安裝了sysdig的環境中複製文件:

快速解釋下每個參數:

-r capture.scap 讀取捕獲文件

-pk 列印Kubernetes部分到stdout中

-NA 顯示ASCII輸出

以及雙引號中是過濾內容。Sysdig能夠理解Kubernetes語義,因此我們可以過濾來自名稱空間critical-app中的任何容器或任何名為skydns的進程的套接字IPv4或IPv6上的流量。加入proc.name = skydns因為這是內部Kubernetes DNS解析器,並且作為Kubernetes基礎結構的一部分運行在我們的命名空間之外。

Sysdig也有一個互動式的ncurses介面。

為了跟隨此服務發現故障排除示例,你可以下載捕獲文件capture.scap[5]並使用sysdig自行查看它。

我們立即看到curl如何嘗試解析域名,但在DNS查詢有效載荷上我們有些奇怪(10049):backend.critical-app.svc.cluster.local.critical-app.svc.cluster.local。看上去由於某些原因,curl不識別已經給定的FQDN,並且決定追加一個搜索域。

SkyDNS發送請求(10097)到etcd的API(/local/cluster/svc/critical-app/local/cluster/svc/critical-app/backend),顯然etcd不能識別這個service,然後返回(10167)「Key not found」。這通過DNS查詢響應傳回給curl。

curl沒有放棄並再次嘗試(10242),不過這次用的是backend.critical-app.svc.cluster.local.svc.cluster.local。看起來這次curl嘗試將critical-app這個追加搜索域去除,使用一個不同的搜索域。顯然,當請求到達etcd(10247)時,再次失敗(10345)。

curl會再次嘗試,我們可以看這次的DNS查詢請求(10418),加上了cluster.local變成backend.critical-app.svc.cluster.local.cluster.local。這次etcd請求(10479)同樣失敗(10524)。

對於未經訓練的人來說,可能看起來我們發現了這個問題:一堆無效的請求。但實際上這不是事實,如果我們查看時間戳,第一個etcd請求(10097)和最後一個(10479)之間的差異,第二列中的時間戳相距小於10ms。而我們正在尋找一個秒數問題,而不是毫秒——那麼等待的時間在哪裡?

當我們繼續瀏覽捕獲文件時,我們可以看到curl不停止嘗試使用DNS查詢到SkyDNS,現在使用backend.critical-app.svc.cluster.local.localdomain(10703)。這個.localdomain不被SkyDNS識別為Kubernetes的內部域,因此它決定將這個查詢轉發給它的上游DNS解析器(10691),而不是去etcd進行服務發現。

掃描時間戳列時,我們發現SkyDNS發出請求後第一個較大的間隙,然後等待大約4秒(10718-58215)。鑒於.localdomain不是有效的TLD(頂級域名),上游伺服器將只是忽略此請求。超時後,SkyDNS再次嘗試使用相同的查詢(75923),再等待幾秒鐘(75927-104208)。總的來說,我們一直在等待大約8秒鐘,以查找不存在並且被忽略的DNS條目。

但最後,它一切正常!為什麼?curl停止嘗試修補事物並應用搜索域。當我們在命令行中輸入時,它會逐字嘗試域名。SkyDNS通過etcd服務發現API請求解析DNS請求(104406)。打開一個與服務IP地址(107992)的連接,然後使用iptables將其轉發給Pod,並且HTTP響應返回到curl容器(108024)。

通過系統層面的情況,我們可以得出結論:造成這個問題的根本原因有兩個方面。首先,當我給curl一個FQDN時,它不相信我並試圖應用搜索域演算法。其次,.localdomain不應該存在,因為它在我們的Kubernetes集群中是不可路由的。

如果你認為這是通過使用tcpdump也能完成,只是你還沒嘗試。我能100%肯定它不會被安裝在你的容器內,你可以在主機外部運行它,但祝你找到與對應Kubernetes調度容器的網路命名空間匹配的網路介面。請繼續閱讀:我們還沒有完成故障排除。

Kubernetes故障排除之DNS解析

讓我們看看resolv.conf文件中的內容。容器可能已經不存在了,或者curl調用後文件可能已經改變。但是我們有一個包含發生了所有事情的捕獲文件。

通常情況下,容器的運行時間與進程內運行的時間一樣長,當進程結束時容器就消失了。這是對容器進行故障排除最具挑戰性的部分之一。我們如何探索已經消失的東西?我們如何重現發生的事情?在這些情況下,Sysdig捕獲文件非常有用。

我們來分析捕獲文件,但不是過濾網路流量,我們將在這次對resolv文件進行過濾。我們希望看到resolv.conf與curl讀取的完全一樣,以確認我們的想法,它包含localdomain。

這是使用sysdig的一種新的方式:

-c echo_fds 使用Sysdig chisel——附加腳本——用以聚合信息並格式化輸出。此外,過濾器僅包含文件描述符上的IO活動,該文件描述符是一個文件,名稱為/etc/resolv.conf,正是我們所要尋找的。

通過系統調用,我們看到有一個選項叫做ndots。 此選項是curl不信任我們的FQDN並試圖首先追加所有搜索域的原因。如果你閱讀了manpage[6],就會知道ndots會強制libc,任何小於5個點的域名解析都不會被視為fqdn,但會嘗試首先追加所有搜索域。ndots有一個很好的理由,所以我們可以執行 curl backend。但是誰在那裡添加了localdomain?

Kubernetes故障排除之使用Docker運行容器

我們不想在沒有找到這個本地域的罪魁禍首的情況下完成我們的故障排除。 這樣,我們可以責怪軟體而不是人,是Docker加了搜索域?或者Kubernetes在創建容器時指導Docker這麼做?

既然我們知道Kubernetes和Docker之間的所有控制通信都是通過Unix套接字完成的,我們可以使用它來過濾掉所有的東西:

這一次,我們將使用一個非常棒的過濾器的來捕捉現場 evt.buffer containers。 這個過濾器需要所有的事件緩衝區,如果它包含我們正在尋找的字元串,將被我們的chisel捕獲並格式化輸出。

現在我需要創建一個新的客戶端來窺探容器編排時發生的情況:

可以看到,Kubernetes中的hyperkube使用Docker API在/var/run/docker.sock上寫了一個HTTP POST請求到/containers/create。如果我們通讀它,我們會發現這個請求包含一個選項「DnsSearch」:[「critical-app.svc.cluster.local」,「svc.cluster.local」,「cluster.local」,「localdomain」]。Kubernetes,我們抓到你了!很可能它出於某種原因,就像我的本地開發機器設置了該搜索域一樣。無論如何,這是一個不同的故事。

總結

準確地再現容器內發生的事情可能會非常具有挑戰性,因為它們在進程死亡或剛剛結束時終止。Sysdig捕獲通過系統調用包含所有信息,包括網路流量、文件系統I/O和進程行為,提供故障排除所需的所有數據。

在容器環境中進行故障排除時,能夠過濾和添加容器上下文信息(如Docker容器名稱或Kubernetes元數據)使我們的排查過程更加輕鬆。

Sysdis在所有主流Linux發行版、OSX以及Windows上都能使用,下載[7]它獲得最新版本。Sysdig是一個開源工具,但該項目背後的公司也提供了一個商業產品[8]來監視和排除多個主機上的容器和微服務。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Docker 的精彩文章:

容器化RDS:PersistentLocalVolumes和VolumeScheduling
TalkingData的Spark On Kubernetes實踐

TAG:Docker |