1.存活探針
使用Kubernetes的一個主要好處是,可以給Kubernetes—個容器列表來由其保持容器在集群中的運行。可以通過讓Kubernetes創建pod資源,為其選擇一個工作節點並在該節點上運行該pod的容器來完成此操作。但是,如果其中一個容器終止,或一個pod的所有容器都終止,怎么辦?
只要將pod調度到某個節點,該節點上的Kubelet就會運行pod的容器,從此只要該pod存在,就會保持運行。如果容器的主進程崩潰,Kubelet將重啟容器。如果應用程序中有一個導致它每隔一段時間就會崩潰的bug, Kubernetes會自動重啟應用程序,所以即使應用程序本身沒有做任何特殊的事,在Kubernetes中運行也能自動獲得自我修復的能力。
即使進程沒有崩潰,有時應用程序也會停止正常工作。例如,具有內存泄漏的 Java應用程序將開始拋出OutOfMemoryErrors,但JVM進程會一直運行。如果有一種方法,能讓應用程序向Kubernetes發出信號,告訴Kubernetes它運行異常並讓 Kubernetes重新啟動,那就很棒了。
我們已經說過,一個崩潰的容器會自動重啟,所以也許你會想到,可以在應用中捕獲這類錯誤,並在錯誤發生時退出該進程。當然可以這樣做,但這仍然不能解決所有的問題。
例如,你的應用因為無限循環或死鎖而停止響應。為確保應用程序在這種情況下可以重新啟動,必須從外部檢查應用程序的運行狀況,而不是依賴於應用的內部檢測。
1.1 介紹存活探針
Kubernetes可以通過存活探針(liveness probe)檢查容器是否還在運行。可以為pod中的每個容器單獨指定存活探針。如果探測失敗,Kubernetes將定期執行探針並重新啟動容器。
Kubernetes有以下三種探測容器的機制:
HTTPGET探針對容器的IP地址(你指定的端口和路徑)執行HTTPGET請求。
-
- 如果探測器收到響應,並且響應狀態碼不代表錯誤(換句話說,如果HTTP響應狀態碼是2xx或3xx),則認為探測成功。如果服務器返回錯誤響應狀態碼或者根本沒有響應,那么探測就被認為是失敗的,容器將被重新啟動。
- TCP套接字探針嘗試與容器指定端口建立TCP連接。如果連接成功建立,則探測成功。否則,容器重新啟動。
- Exec探針在容器內執行任意命令,並檢查命令的退出狀態碼。如果狀態碼是0,則探測成功。所有其他狀態碼都被認為失敗。
1.2 創建基於HTTP的存活探針
來看看如何為一個Node.js應用添加一個存活探針。因為它是一個Web應用程序,所以添加一個存活探針來檢查其Web服務器是否提供請求是有意義的。但是因為這個Node.js應用程序太簡單了,所以不得不人為地讓它失敗。
要正確演示存活探針,需要稍微修改應用程序。在第五個請求之后,給每個請求返回HTTP狀態碼500 (Internal Server Error)--你的應用程序將正確處理前
五個客戶端請求,之后每個請求都會返回錯誤。多虧了存活探針,應用在這個時候會重啟,使其能夠再次正確處理客戶端請求。
你將創建一個包含HTTPGET存活探針的新pod,下面的代碼顯示了pod的yaml。
#代碼4.1 將存活探針添加到pod apiVersion: v1 kind: Pod metadata: name: kubia-liveness spec: containers: - image: luksa/kubia-unhealthy #這個鏡像包含了壞掉的應用 name: kubia livenessProbe: #一個HTTP GET存活探針 httpGet: path: / #請求 port: 8080 #探針連接的網絡端口
該pod的描述文件定義了一個httpGet存活探針,該探針告訴Kubernetes定期在端口 8080路徑上執行HTTP GET請求,以確定該容器是否健康。這些請求在容器運行后立即開始。
經過五次這樣的請求(或實際的客戶端請求)后,你的應用程序開始返回HTTP狀態碼500, Kubernetes會認為探測失敗並重啟容器。
1.3 使用存活探針
要查看存活探針是如何工作的,請嘗試立即創建該pod。大約一分半鍾后,容器將重啟。可以通過運行kubectl get看到:
$ kubectl get po kubia-liveness NAME READY STATUS RESTARTS AGE kubia-liveness 1/1 Running 1 2m
RESTARTS列顯示pod的容器已被重啟一次(如果你再等一分半鍾,它會再次重啟,然后無限循環下去)。
可以通過查看kubectl describe的內容來了解為什么必須重啟容器,如下面的代碼清單所示
$ kubectl describe po kubia-liveness Name: kubia-liveness ... Containers: kubia: Container ID: docker://480986f8 Image: luksa/kubia-unhealthy Image ID: docker://sha256:2b208508 Port: State: Running Started: Sun, 14 May 2017 11:41:40 +0200 #容器正在運行 Last State: Terminated #先前的容器由於發生錯誤被終止,返回碼是147 Reason: Error Exit Code: 137 Started: Mon, 01 Jan 0001 00:00:00 +0000 Finished: Sun, 14 May 2017 11:41:38 +0200 Ready: True Restart Count: 1 #該容器已被重啟一次 Liveness: http-get http://:8080/ delay=0s timeout=1s period=10s #success=1 #failure=3 ... Events: ... Killing container with id docker://95246981:pod "kubia-liveness ..." container "kubia" is unhealthy, it will be killed and re-created.
可以看到容器現在正在運行,但之前由於錯誤而終止。退出代碼為137,這有特殊的含義——表示該進程由外部信號終止。數字137是兩個數字的總和:128 + x,其中x是終止進程的信號編號。在這個例子中,x等於9,這是SIGKILL的信號編號,意味着這個進程被強行終止。
在底部列出的事件顯示了容器為什么終止一一Kubernetes發現容器不健康,所以終止並重新創建。
注意:當容器被強行終止時,會創建一個全新的容器——而不是重啟原來的容器。
1.4 配置存活探針的附加屬性
你可能己經注意到,kubectl describe還顯示關於存活探針的附加信息:
Liveness http-get http://:8080/ delay=0s timeout=1s period=1Os #success=1 #failure=3
除了明確指定的存活探針選項,還可以看到其他屬性,例如delay (延遲)、timeout (超時)、period (周期)等。delay=0s部分顯示在容器啟動后立即開始探測。timeout僅設置為1秒,因此容器必須在1秒內進行響應,不然這次探測記作失敗。每10秒探測一次容器(period=lOs),並在探測連續三次失敗 (#failure=3)后重啟容器。
定義探針時可以自定義這些附加參數。例如,要設置初始延遲,請將 initialDelaySeconds屬性添加到存活探針的配置中,如下面的代碼清單所示。
#代碼4.3 具有初始延遲的存活探針:kubia-liveness-probe-initial-delay.yaml
apiVersion: v1 kind: Pod metadata: name: kubia-liveness spec: containers: - image: luksa/kubia-unhealthy name: kubia livenessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 15 #kubernetes會在第一次探測前等待15秒,為了讓有些啟動長時間的程序有個緩沖 timeoutSeconds: 10 #超過10s或者返回碼不在200~300內,就緒檢查就失敗 periodSeconds: 5 #每5秒檢查一次
2.就緒探針
如果pod沒有准備好,如何處理服務請求呢?
有些pod可能需要時間來加載配置或數據,或者可能需要執行預熱過程以防止第一個用戶請求時間太長影響了用戶體驗。在這種情況下,不希望該pod立即開始接收請求,尤其是在運行的實例可以正確快速地處理請求的情況下。不要將請求轉發到正在啟動的pod中,直到完全准備就緒。
2.1 介紹就緒探針
了解了存活探針,以及它們如何通過確保異常容器自動重啟來保持應用程序的正常運行。與存活探針類似,Kubernetes還允許為容器定義准備就緒探針。
就緒探測器會定期調用,並確定特定的pod是否接收客戶端請求。當容器的准備就緒探測返回成功時,表示容器已准備好接收請求。
這個准備就緒的概念顯然是每個容器特有的東西。Kubernetes只能檢查在容器中運行的應用程序是否響應一個簡單的GET/請求,或者它可以響應特定的URL路徑(該URL導致應用程序執行一系列檢查以確定它是否准備就緒)。考慮到應用程序的具體情況,這種確切的准備就緒的判定是應用程序開發人員的責任。
就緒探針的類型
像存活探針一樣,就緒探針有三種類型:
-
- Exec探針,執行進程的地方。容器的狀態由進程的退出狀態代碼確定。
- HTTP GET探針,向容器發送HTTP GET請求,通過響應HTTP狀態代碼,判斷容器是否准備好。
- TCP socket探針,它打開一個TCP連接到容器的指定端口。如果連接己建立,則認為容器己准備就緒。
了解就緒探針的操作
啟動容器時,可以為Kubernetes配置一個等待時間,經過等待時間后才可以執行第一次准備就緒檢查。之后,它會周期性地調用探針,並根據就緒探針的結果采取行動。如果某個pod報告它尚未准備就緒,則會從該服務中刪除該pod。如果pod再次准備就緒,則重新添加pod。
與存活探針不同,如果容器未通過准備檢查,則不會被終止或重新啟動。這是存活探針與就緒探針之間的重要區別。存活探針通過殺死異常的容器並用新的正常 容器替代它們來保持pod正常工作,而就緒探針確保只有准備好處理請求的pod才可以接收它們(請求)。這在容器啟動時最為必要,當然在容器運行一段時間后也是有用的。
如圖5.11所示,如果一個容器的就緒探測失敗,則將該容器從端點對象中移除。 連接到該服務的客戶端不會被重定向到pod。這和pod與服務的標簽選擇器完全不匹配的效果相同。
了解就緒探針的重要性
設想一組pod(例如,運行應用程序服務器的pod)取決於另一個pod(例如,后端數據庫)提供的服務。如果任何一個前端連接點出現連接問題並且無法再訪問數據庫,那么就緒探針可能會告知Kubernetes該pod沒有准備好處理任何請求。如果其他pod實例沒有遇到類似的連接問題,則它們可以正常處理請求。就緒探針確保客戶端只與正常的pod交互,並且永遠不會知道系統存在問題。
2.2 向pod 添加就緒探針
接下來,將通過修改Replication Controller(deployment也一樣)的pod模板來為現有的pod添加就緒探針。
向pod template添加就緒探針
可以通過kubectl edit命令來向己存在的ReplicationController中的pod模板添加探針。
$ kubectl edit rc kubia
當在文本編輯器中打開ReplicationControlier的YAML時,在pod模板中查找容器規格,並將以下就緒探針定義添加到spec.template.spec.containers下的第一個容器。YAML看起來應該就像下面的代碼清單。
#代碼5.17 RC創建帶有就緒探針的pod:kubia-rc-readinessprobe.yaml
apiVersion: v1 kind: ReplicationController metadata: name: kubia spec: replicas: 3 selector: app: kubia template: metadata: labels: app: kubia spec: containers: - name: kubia image: luksa/kubia ports: - name: http containerPort: 8080 readinessProbe: #pod中每個容器都會有一個就緒探針 exec: #使用exec的方式 command: - ls - /var/ready
就緒探針將定期在容器內執行ls/var/ready命令。如果文件存在,則ls命令返回退出碼0,否則返回非零的退出碼。如果文件存在,則就緒探針將成功;否則,它會失敗。
定義這樣一個奇怪的就緒探針的原因是,可以通過創建或刪除有問題的文件來觸發結果。該文件尚不存在,所以所有的pod現在應該報告沒有准備好,是這樣的嗎?其實並不完全是,正如在前面章節中了解的那樣,更改ReplicationController的pod模板對現有的pod沒有影響。
換句話說,現有的所有pod仍沒有定義准備就緒探針。可以通過使用kubectl get pods列出pod並查看READY列。需要刪除pod並讓它們通過ReplicationController重新創建。新的pod將進行就緒檢查會一直失敗,並且不會將其作為服務的端點,直到在每個pod中創建/var/ready文件。
觀察並修改pod 就緒狀態
再次列出pod並檢查它們是否准備好:
$ kubectl get po NAME READY STATUS RESTARTS AGE kubia-2rlqb 0/1 Running 0 lm kubia-3raxl 0/1 Running 0 lm kubia-3yw4s 0/1 Running 0 lm
READY列顯示出沒有一個容器准備好。現在通過創建/var/ready文件使其中一個文件的就緒探針返回成功,該文件的存在可以模擬就緒探針成功:
使用kubectl exec命令在kubia-2rlqb的pod容器內執行touch命令。 如果文件尚不存在,touch命令會創建該文件。就緒探針命令現在應該返回退出碼0, 這意味着探測成功,並且現在應該顯示pod己准備就緒。現在去查看其狀態:
$ kubectl get po kubia-2rlqb
NAME READY STATUS RESTARTS AGE
kubia-2rlqb 0/1 Running 0 2
該pod還沒有准備好。有什么不對或者這是預期的結果嗎?用kubectl describe來獲得更詳細的關於pod的信息。輸出應該包含以下內容:
Readiness: exec [ls /var/ready] delay=0s timeout=1s period=10s #success=1 #failure=3
准備就緒探針會定期檢查--默認情況下每10秒檢查一次。由於尚未調用就緒探針,因此容器未准備好。但是最晚10秒鍾內,該pod應該己經准備就緒,其IP應該列為service的endpoint(運行kubectl get endpoint kubia-loadbalancer來確認)。
服務打向單獨pod
現在可以點擊幾次服務網址,查看每個請求都被重定向到這個pod:
$ curl http://130.211.53.173 You've hit kubia-2rlqb $ curl http://130.211.53.173 You've hit kubia-2rlqb $ curl http://130.211.53.173 You've hit kubia-2rlqb
即使有三個pod正在運行,但只有一個pod報告己准備好,因此是唯一的pod接收請求。如果現在刪除該文件,則將再次從該服務中刪除該容器。
2.3 了解就緒探針的實際作用
此模擬就緒探針僅用於演示就緒探針的功能。在實際應用中,應用程序是否可以(並且希望)接收客戶端請求,決定了就緒探測應該返回成功或失敗。
應該通過刪除pod或更改pod標簽而不是手動更改探針來從服務中手動移除pod。
提示:如果想要從某個服務中手動添加或刪除pod,請將enabled=true作為標簽添加到pod,以及服務的標簽選擇器中。當想要從服務中移除pod時,刪除標簽。
務必定義就緒探針,就緒探針當然在容器運行一段時間后也是有用的。可以檢測失敗的容器並移除。
3.總結
1.使用存活探針,讓Kubernetes在容器不再健康的情況下立即重啟它(應用程序定義了健康的條件)。
2.如果定義了就緒探針,請確保它返回成功;否則該pod不會成為服務的一部分。