Kubernetes應用健康檢查

振宇要低調發表於2017-03-15

  在實際生產環境中,想要使得開發的應用程式完全沒有bug,在任何時候都執行正常,幾乎 是不可能的任務。因此,我們需要一套管理系統,來對使用者的應用程式執行週期性的健康檢查和修復操作。這套管理系統必須執行在應用程式之外,這一點非常重要一一如果它是應用程式的一部分,極有可能會和應用程式一起崩潰。因此,在Kubernetes中,系統和應用程式的健康檢查是由Kubelet來完成的。

1、程式級健康檢查

  最簡單的健康檢查是程式級的健康檢查,即檢驗容器程式是否存活。這類健康檢查的監控粒 度是在Kubernetes叢集中執行的單一容器。Kubelet會定期通過Docker Daemon獲取所有Docker程式的執行情況,如果發現某個Docker容器未正常執行,則重新啟動該容器程式。目前,程式級的健康檢查都是預設啟用的。

2.業務級健康檢查

  在很多實際場景下,僅僅使用程式級健康檢查還遠遠不夠。有時,從Docker的角度來看,容器程式依舊在執行;但是如果從應用程式的角度來看,程式碼處於死鎖狀態,即容器永遠都無法正常響應使用者的業務

  為了解決以上問題,Kubernetes引人了一個在容器內執行的活性探針(liveness probe)的概念,以支援使用者自己實現應用業務級的健康檢查。這些檢查項由Kubelet代為執行,以確保使用者的應用程式正確運轉,至於什麼樣的狀態才算“正確”,則由使用者自己定義。Kubernetes支援3種型別的應用健康檢查動作,分別為HTTP Get、Container Exec和TCP Socket。個人感覺exec的方式還是最通用的,因為不是每個服務都有http服務,但每個服務都可以在自己內部定義健康檢查的job,定期執行,然後將檢查結果儲存到一個特定的檔案中,外部探針就不斷的檢視這個健康檔案就OK了。

2.1 Container Exec

  Kubelet將在使用者容器內執行一次命令,如果命令執行的退出碼為0,則認為容器運轉正常,否則認為容器運轉不正常。其中執行命令的預設目錄是容器檔案系統的根目錄/,要執行的命令在Pod配置檔案中定義。每進行一次Container Exec健康檢查,都會執行一次livenessprobe:exec:command段下的Shell命令。以下給出exec探針的示例:

[root@k8s-master livenessProbe]# cat test-livenessprobe-hostpath.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    name: test-livenessprobe-hostpath
  name: test-livenessprobe-hostpath
spec:
  containers:
    - name: test-livenessprobe-hostpath
      image: registry:5000/back_demon:1.0
      volumeMounts:
       - name: testhost
         mountPath: /home/laizy/test/hostpath
         readOnly: false
      livenessProbe:
        exec:
          command:
          - cat
          - /home/laizy/test/hostpath/healthy
        initialDelaySeconds: 5
        periodSeconds: 5
      command:
      - /run.sh
  volumes:
  - name: testhost
    hostPath:
     path: /home/testhost

  由yaml的配置可以看出,健康探針主要探測的是/home/laizy/test/hostpath/下是否存在healthy檔案,對應的是宿主機上/home/testhost這個資料夾。若不存在則判定不健康,若存在則健康。筆者在實驗的過程中發現,當在宿主機上刪除這個檔案的時候,大概需要40S的時間,系統才會判定pod失敗,並將其刪除;之後一直不斷重啟,且不會將pod排程到別的node上;當在宿主機上重新生成這個檔案之後,大概需要四五分鐘的時間,pod一直處於CrashLoopBackOff的狀態,之後才正常提供服務。對於這兩個時間的產生,還需要進一步的探究其原理。

2.1 HTTP Get

  Kubelet將呼叫容器內Web應用的web hook,如果返回的HTTP狀態碼在200和399之間,則認為容器運轉正常,否則認為容器運轉不正常。每進行一次HTTP健康檢查都會訪問一次指定的URL。給出httpGet的簡單示例如下:

[root@k8s-master livenessProbe]# cat test-livenessprobe.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    name: test-livenessprobe
  name: test-livenessprobe
spec:
  containers:
    - name: test-livenessprobe
      image: registry:5000/back_demon:1.0
      livenessProbe:
        httpGet:
          path: /starott_cloud_client/test/overview-frontend
          port: 8080
        initialDelaySeconds: 15
        periodSeconds: 5
        timeoutSeconds: 1
      command:
      - /run.sh

在容器內部kill掉jboss程式之後(我的映象用指令碼run.sh啟動,kill掉業務主程式之後,還可以通過其他的程式將容器“卡住”),模擬出呼叫http介面返回不在200~399之間,在node的/var/log/messages下會出現如下日誌,並隨後將pod建立。

Apr  6 13:22:03 k8s-node-1 kubelet: I0406 13:22:03.470882   19861 docker_manager.go:2015] pod "test-livenessprobe_default(77b73469-1a88-11e7-b3d5-fa163ebba51b)" container "test-livenessprobe" is unhealthy, it will be killed and re-created.
Apr  6 13:22:03 k8s-node-1 dockerd-current: time="2017-04-06T13:22:03.471442565+08:00" level=info msg="{Action=stop, LoginUID=4294967295, PID=19861}"
Apr  6 13:22:33 k8s-node-1 dockerd-current: time="2017-04-06T13:22:33.472842885+08:00" level=info msg="Container 77c700d8564f2d7b8b0b455563b7530f5657df9b8a0de528587c6e0fb8a28237 failed to exit within 30 seconds of signal 15 - using the force"

2.3 TCP Socket

  理論上Kubelet將會嘗試開啟一個到使用者容器的Socket連線。如果能夠建立這條連線,則可以認為容器運轉正常,否則認為容器運轉不正常。

  不論哪種檢查型別,一旦Kubelet發現容器運轉不正常,就會重新啟動該容器。容器的健康檢查行為在容器配置檔案的livenessprobe欄位下配置。需要注意的是,livenessprobe:initialDelaySecods欄位代表了一個從容器啟動到執行健康檢查的延遲時間,設計這個延遲時間的目的是讓容器程式有時間完成必要的初始化工作。

相關文章