做者 | 莫源 阿里巴巴技術專家html
首先來看一下,整個需求的來源:當把應用遷移到 Kubernetes 以後,要如何去保障應用的健康與穩定呢?其實很簡單,能夠從兩個方面來進行加強:node
從可觀測性上來說,能夠在三個方面來去作加強:docker
當出現了問題以後,首先要作的事情是要下降影響的範圍,進行問題的調試與診斷。最後當出現問題的時候,理想的情況是:能夠經過和 K8s 集成的自愈機制進行完整的恢復。shell
本小節爲你們介紹 Liveness probe 和 eadiness probe。性能優化
Liveness probe 也叫就緒指針,用來判斷一個 pod 是否處在就緒狀態。當一個 pod 處在就緒狀態的時候,它纔可以對外提供相應的服務,也就是說接入層的流量才能打到相應的 pod。當這個 pod 不處在就緒狀態的時候,接入層會把相應的流量從這個 pod 上面進行摘除。bash
來看一下簡單的一個例子:微信
以下圖其實就是一個 Readiness 就緒的一個例子:網絡
當這個 pod 指針判斷一直處在失敗狀態的時候,其實接入層的流量不會打到如今這個 pod 上。app
當這個 pod 的狀態從 FAIL 的狀態轉換成 success 的狀態時,它纔可以真實地承載這個流量。<br /> <br />Liveness 指針也是相似的,它是存活指針,用來判斷一個 pod 是否處在存活狀態。當一個 pod 處在不存活狀態的時候,會出現什麼事情呢?less
這個時候會由上層的判斷機制來判斷這個 pod 是否須要被從新拉起。那若是上層配置的重啓策略是 restart always 的話,那麼此時這個 pod 會直接被從新拉起。
接下來看一下 Liveness 指針和 Readiness 指針的具體的用法。
Liveness 指針和 Readiness 指針支持三種不一樣的探測方式:
從探測結果來說主要分爲三種:
那在 kubelet 裏面有一個叫 ProbeManager 的組件,這個組件裏面會包含 Liveness-probe 或 Readiness-probe,這兩個 probe 會將相應的 Liveness 診斷和 Readiness 診斷做用在 pod 之上,來實現一個具體的判斷。
下面介紹這三種方式不一樣的檢測方式的一個 yaml 文件的使用。
首先先看一下 exec,exec 的使用其實很是簡單。以下圖所示,你們能夠看到這是一個 Liveness probe,它裏面配置了一個 exec 的一個診斷。接下來,它又配置了一個 command 的字段,這個 command 字段裏面經過 cat 一個具體的文件來判斷當前 Liveness probe 的狀態,當這個文件裏面返回的結果是 0 時,或者說這個命令返回是 0 時,它會認爲此時這個 pod 是處在健康的一個狀態。
那再來看一下這個 httpGet,httpGet 裏面有一個字段是路徑,第二個字段是 port,第三個是 headers。這個地方有時須要經過相似像 header 頭的一個機制作 health 的一個判斷時,須要配置這個 header,一般狀況下,可能只須要經過 health 和 port 的方式就能夠了。
第三種是 tcpSocket,tcpSocket 的使用方式其實也比較簡單,你只須要設置一個檢測的端口,像這個例子裏面使用的是 8080 端口,當這個 8080 端口 tcp connect 審覈正常被創建的時候,那 tecSocket,Probe 會認爲是健康的一個狀態。
此外還有以下的五個參數,是 Global 的參數。
接下來對 Liveness 指針和 Readiness 指針進行一個簡單的總結。
Liveness 指針是存活指針,它用來判斷容器是否存活、判斷 pod 是否 running。若是 Liveness 指針判斷容器不健康,此時會經過 kubelet 殺掉相應的 pod,並根據重啓策略來判斷是否重啓這個容器。若是默認不配置 Liveness 指針,則默認狀況下認爲它這個探測默認返回是成功的。
Readiness 指針用來判斷這個容器是否啓動完成,即 pod 的 condition 是否 ready。若是探測的一個結果是不成功,那麼此時它會從 pod 上 Endpoint 上移除,也就是說從接入層上面會把前一個 pod 進行摘除,直到下一次判斷成功,這個 pod 纔會再次掛到相應的 endpoint 之上。
對於檢測失敗上面來說 Liveness 指針是直接殺掉這個 pod,而 Readiness 指針是切掉 endpoint 到這個 pod 之間的關聯關係,也就是說它把這個流量從這個 pod 上面進行切掉。
Liveness 指針適用場景是支持那些能夠從新拉起的應用,而 Readiness 指針主要應對的是啓動以後沒法當即對外提供服務的這些應用。
在使用 Liveness 指針和 Readiness 指針的時候有一些注意事項。由於不管是 Liveness 指針仍是 Readiness 指針都須要配置合適的探測方式,以避免被誤操做。
第一個是調大超時的閾值,由於在容器裏面執行一個 shell 腳本,它的執行時長是很是長的,平時在一臺 ecs 或者在一臺 vm 上執行,可能 3 秒鐘返回的一個腳本在容器裏面須要 30 秒鐘。因此這個時間是須要在容器裏面事先進行一個判斷的,那若是能夠調大超時閾值的方式,來防止因爲容器壓力比較大的時候出現偶發的超時;
第二個是調整判斷的一個次數,3 次的默認值其實在比較短週期的判斷週期之下,不必定是最佳實踐,適當調整一下判斷的次數也是一個比較好的方式;
第三個是 exec,若是是使用 shell 腳本的這個判斷,調用時間會比較長,比較建議你們可使用相似像一些編譯性的腳本 Golang 或者一些 C 語言、C++ 編譯出來的這個二進制的 binary 進行判斷,那這種一般會比 shell 腳本的執行效率高 30% 到 50%;
第四個是若是使用 tcpSocket 方式進行判斷的時候,若是遇到了 TLS 的服務,那可能會形成後邊 TLS 裏面有不少這種未健全的 tcp connection,那這個時候須要本身對業務場景上來判斷,這種的連接是否會對業務形成影響。
接下來給你們講解一下在 K8s 中常見的問題診斷。
首先要了解一下 K8s 中的一個設計理念,就是這個狀態機制。由於 K8s 是整個的一個設計是面向狀態機的,它裏面經過 yaml 的方式來定義的是一個指望到達的一個狀態,而真正這個 yaml 在執行過程當中會由各類各樣的 controller來負責總體的狀態之間的一個轉換。
好比說上面的圖,其實是一個 Pod 的一個生命週期。剛開始它處在一個 pending 的狀態,那接下來可能會轉換到相似像 running,也可能轉換到 Unknown,甚至能夠轉換到 failed。而後,當 running 執行了一段時間以後,它能夠轉換到相似像 successded 或者是 failed,而後當出如今 unknown 這個狀態時,可能因爲一些狀態的恢復,它會從新恢復到 running 或者 successded 或者是 failed 。
其實 K8s 總體的一個狀態就是基於這種相似像狀態機的一個機制進行轉換的,而不一樣狀態之間的轉化都會在相應的 K8s對象上面留下來相似像 Status 或者像 Conditions 的一些字段來進行表示。
像下面這張圖其實表示的就是說在一個 Pod 上面一些狀態位的一些展示。
好比說在 Pod 上面有一個字段叫 Status,這個 Status 表示的是 Pod 的一個聚合狀態,在這個裏面,這個聚合狀態處在一個 pending 狀態。
而後再往下看,由於一個 pod 裏面有多個 container,每一個 container 上面又會有一個字段叫 State,而後 State 的狀態表示當前這個 container 的一個聚合狀態。那在這個例子裏面,這個聚合狀態處在的是 waiting 的狀態,那具體的緣由是由於什麼呢?是由於它的鏡像沒有拉下來,因此處在 waiting 的狀態,是在等待這個鏡像拉取。而後這個 ready 的部分呢,目前是 false,由於它這個進行目前沒有拉取下來,因此這個 pod 不可以正常對外服務,因此此時 ready 的狀態是未知的,定義爲 false。若是上層的 endpoint 發現底層這個 ready 不是 true 的話,那麼此時這個服務是沒有辦法對外服務的。
再往下是 condition,condition 這個機制表示是說:在 K8s 裏面有不少這種比較小的這個狀態,而這個狀態之間的聚合會變成上層的這個 Status。那在這個例子裏面有幾個狀態,第一個是 Initialized,表示是否是已經初始化完成?那在這個例子裏面已是初始化完成的,那它走的是第二個階段,是在這個 ready 的狀態。由於上面幾個 container 沒有拉取下來相應的鏡像,因此 ready 的狀態是 false。
而後再往下能夠看到這個 container 是否 ready,這裏能夠看到是 false,而這個狀態是 PodScheduled,表示說當前這個 pod 是不是處在一個已經被調度的狀態,它已經 bound 在如今這個 node 之上了,因此這個狀態也是 true。
那能夠經過相應的 condition 是 true 仍是 false 來判斷總體上方的這個狀態是不是正常的一個狀態。而在 K8s 裏面不一樣的狀態之間的這個轉換都會發生相應的事件,而事件分爲兩種: 一種叫作 normal 的事件,一種是 warning 事件。你們能夠看見在這第一條的事件是有個 normal 事件,而後它相應的 reason 是 scheduler,表示說這個 pod 已經被默認的調度器調度到相應的一個節點之上,而後這個節點是 cn-beijing192.168.3.167 這個節點之上。
再接下來,又是一個 normal 的事件,表示說當前的這個鏡像在 pull 相應的這個 image。而後再往下是一個 warning 事件,這個 warning 事件表示說 pull 這個鏡像失敗了。
以此類推,這個地方表示的一個狀態就是說在 K8s 裏面這個狀態機制之間這個狀態轉換會產生相應的事件,而這個事件又經過相似像 normal 或者是 warning 的方式進行暴露。開發者能夠經過相似像經過這個事件的機制,能夠經過上層 condition Status 相應的一系列的這個字段來判斷當前這個應用的具體的狀態以及進行一系列的診斷。
本小節介紹一下常見應用的一些異常。首先是 pod 上面,pod 上面可能會停留幾個常見的狀態。
第一個就是 pending 狀態,pending 表示調度器沒有進行介入。此時能夠經過 kubectl describe pod 來查看相應的事件,若是因爲資源或者說端口占用,或者是因爲 node selector 形成 pod 沒法調度的時候,能夠在相應的事件裏面看到相應的結果,這個結果裏面會表示說有多少個不知足的 node,有多少是由於 CPU 不知足,有多少是因爲 node 不知足,有多少是因爲 tag 打標形成的不知足。
那第二個狀態就是 pod 可能會停留在 waiting 的狀態,pod 的 states 處在 waiting 的時候,一般表示說這個 pod 的鏡像沒有正常拉取,緣由多是因爲這個鏡像是私有鏡像,可是沒有配置 Pod secret;那第二種是說可能因爲這個鏡像地址是不存在的,形成這個鏡像拉取不下來;還有一個是說這個鏡像多是一個公網的鏡像,形成鏡像的拉取失敗。
第三種是 pod 不斷被拉起,並且能夠看到相似像 backoff 。這個一般表示說 pod 已經被調度完成了,可是啓動失敗,那這個時候一般要關注的應該是這個應用自身的一個狀態,並非說配置是否正確、權限是否正確,此時須要查看的應該是 pod 的具體日誌。
第四種 pod 處在 running 狀態,可是沒有正常對外服務。那此時比較常見的一個點就多是因爲一些很是細碎的配置,相似像有一些字段可能拼寫錯誤,形成了 yaml 下發下去了,可是有一段沒有正常地生效,從而使得這個 pod 處在 running 的狀態沒有對外服務,那此時能夠經過 apply-validate-f pod.yaml 的方式來進行判斷當前 yaml 是不是正常的,若是 yaml 沒有問題,那麼接下來可能要診斷配置的端口是不是正常的,以及 Liveness 或 Readiness 是否已經配置正確。
最後一種就是 service 沒法正常工做的時候,該怎麼去判斷呢?那比較常見的 service 出現問題的時候,是本身的使用上面出現了問題。由於 service 和底層的 pod 之間的關聯關係是經過 selector 的方式來匹配的,也就是說 pod 上面配置了一些 label,而後 service 經過 match label 的方式和這個 pod 進行相互關聯。若是這個 label 配置的有問題,可能會形成這個 service 沒法找到後面的 endpoint,從而形成相應的 service 沒有辦法對外提供服務,那若是 service 出現異常的時候,第一個要看的是這個 service 後面是否是有一個真正的 endpoint,其次來看這個 endpoint 是否能夠對外提供正常的服務。
本節講解的是在 K8s 裏面如何進行應用的遠程調試,遠程調試主要分爲 pod 的遠程調試以及 service 的遠程調試。還有就是針對一些性能優化的遠程調試。
首先把一個應用部署到集羣裏面的時候,發現問題的時候,須要進行快速驗證,或者說修改的時候,可能須要相似像登錄進這個容器來進行一些診斷。
好比說能夠經過 exec 的方式進入一個 pod。像這條命令裏面,經過 kubectl exec-it pod-name 後面再填寫一個相應的命令,好比說 /bin/bash,表示但願到這個 pod 裏面進入一個交互式的一個 bash。而後在 bash 裏面能夠作一些相應的命令,好比說修改一些配置,經過 supervisor 去從新拉起這個應用,都是能夠的。
那若是指定這一個 pod 裏面可能包含着多個 container,這個時候該怎麼辦呢?怎麼經過 pod 來指定 container 呢?其實這個時候有一個參數叫作 -c,如上圖下方的命令所示。-c 後面是一個 container-name,能夠經過 pod 在指定 -c 到這個 container-name,具體指定要進入哪一個 container,後面再跟上相應的具體的命令,經過這種方式來實現一個多容器的命令的一個進入,從而實現多容器的一個遠程調試。
那麼 service 的遠程調試該怎麼作呢?service 的遠程調試其實分爲兩個部分:
在反向列入上面有這樣一個開源組件,叫作 Telepresence,它能夠將本地的應用代理到遠程集羣中的一個 service 上面,使用它的方式很是簡單。
首先先將 Telepresence 的一個 Proxy 應用部署到遠程的 K8s 集羣裏面。而後將遠程單一個 deployment swap 到本地的一個 application,使用的命令就是 Telepresence-swap-deployment 而後以及遠程的 DEPLOYMENT_NAME。經過這種方式就能夠將本地一個 application 代理到遠程的 service 之上、能夠將應用在遠程集羣裏面進行本地調試,這個有興趣的同窗能夠到 GitHub 上面來看一下這個插件的使用的方式。
第二個是若是本地應用須要調用遠程集羣的服務時候,能夠經過 port-forward 的方式將遠程的應用調用到本地的端口之上。好比說如今遠程的裏面有一個 API server,這個 API server 提供了一些端口,本地在調試 Code 時候,想要直接調用這個 API server,那麼這時,比較簡單的一個方式就是經過 port-forward 的方式。
它的使用方式是 kubectl port-forward,而後 service 加上遠程的 service name,再加上相應的 namespace,後面還能夠加上一些額外的參數,好比說端口的一個映射,經過這種機制就能夠把遠程的一個應用代理到本地的端口之上,此時經過訪問本地端口就能夠訪問遠程的服務。
最後再給你們介紹一個開源的調試工具,它也是 kubectl 的一個插件,叫 kubectl-debug。咱們知道在 K8s 裏面,底層的容器 runtime 比較常見的就是相似像 docker 或者是 containerd,不管是 docker 仍是 containerd,它們使用的一個機制都是基於 Linux namespace 的一個方式進行虛擬化和隔離的。
一般狀況下 ,並不會在鏡像裏面帶特別多的調試工具,相似像 netstat telnet 等等這些 ,由於這個會形成應用總體很是冗餘。那麼若是想要調試的時候該怎麼作呢?其實這個時候就能夠依賴相似於像 kubectl-debug 這樣一個工具。<br /> <br /> kubectl-debug 這個工具是依賴於 Linux namespace 的方式來去作的,它能夠 datash 一個 Linux namespace 到一個額外的 container,而後在這個 container 裏面執行任何的 debug 動做,其實和直接去 debug 這個 Linux namespace 是一致的。這裏有一個簡單的操做,給你們來介紹一下:
這個地方其實已經安裝好了 kubectl-debug,它是 kubectl 的一個插件。因此這個時候,你能夠直接經過 kubectl-debug 這條命令來去診斷遠程的一個 pod。像這個例子裏面,當執行 debug 的時候,實際上它首先會先拉取一些鏡像,這個鏡像裏面實際上會默認帶一些診斷的工具。當這個鏡像啓用的時候,它會把這個 debug container 進行啓動。與此同時會把這個 container 和相應的你要診斷的這個 container 的 namespace 進行掛靠,也就說此時這個 container 和你是同 namespace 的,相似像網絡站,或者是相似像內核的一些參數,其實均可以在這個 debug container 裏面實時地進行查看。
像這個例子裏面,去查看相似像 hostname、進程、netstat 等等,這些其實都是和這個須要 debug 的 pod 是在同一個環境裏面的,因此你以前這三條命令能夠看到裏面相關的信息。
若是此時進行 logout 的話,至關於會把相應的這個 debug pod 殺掉,而後進行退出,此時對應用其實是沒有任何的影響的。那麼經過這種方式能夠不介入到容器裏面,就能夠實現相應的一個診斷。
此外它還支持額外的一些機制,好比說我給設定一些 image,而後相似像這裏面安裝了的是 htop,而後開發者能夠經過這個機制來定義本身須要的這個命令行的工具,而且經過這種 image 的方式設置進來。那麼這個時候就能夠經過這種機制來調試遠程的一個 pod。
關於 Liveness 和 Readiness 的指針。Liveness probe 就是保活指針,它是用來看 pod 是否存活的,而 Readiness probe 是就緒指針,它是判斷這個 pod 是否就緒的,若是就緒了,就能夠對外提供服務。這個就是 Liveness 和 Readiness 須要記住的部分;
應用診斷的三個步驟:首先 describe 相應的一個狀態;而後提供狀態來排查具體的一個診斷方向;最後來查看相應對象的一個 event 獲取更詳細的一個信息;
提供 pod 一個日誌來定位應用的自身的一個狀態;
遠程調試的一個策略,若是想把本地的應用代理到遠程集羣,此時能夠經過 Telepresence 這樣的工具來實現,若是想把遠程的應用代理到本地,而後在本地進行調用或者是調試,能夠用相似像 port-forward 這種機制來實現。
「 阿里巴巴雲原生微信公衆號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的技術公衆號。」
原文出處:https://www.cnblogs.com/alisystemsoftware/p/11652536.html