k8s之Pod健康檢測

Pod健康檢測機制

對於Pod的健康狀態檢測,kubernetes提供了兩類探針(Probe)來執行對Pod的健康狀態檢測:java

  • LivenessProbe探針:
    用於判斷容器是否存活,即Pod是否爲running狀態,若是LivenessProbe探針探測到容器不健康,則kubelet將kill掉容器,並根據容器的重啓策略是否重啓,若是一個容器不包含LivenessProbe探針,則Kubelet認爲容器的LivenessProbe探針的返回值永遠成功。
  • ReadinessProbe探針:
    用於判斷容器是否啓動完成,即容器的Ready是否爲True,能夠接收請求,若是ReadinessProbe探測失敗,則容器的Ready將爲False,控制器將此Pod的Endpoint從對應的service的Endpoint列表中移除,今後再也不將任何請求調度此Pod上,直到下次探測成功。

每類探針都支持三種探測方法:node

  • exec:經過執行命令來檢查服務是否正常,針對複雜檢測或無HTTP接口的服務,命令返回值爲0則表示容器健康。
  • httpGet:經過發送http請求檢查服務是否正常,返回200-399狀態碼則代表容器健康。
  • tcpSocket:經過容器的IP和Port執行TCP檢查,若是可以創建TCP鏈接,則代表容器健康。

探針探測的結果有如下三者之一:docker

  • Success:Container經過了檢查。
  • Failure:Container未經過檢查。
  • Unknown:未能執行檢查,所以不採起任何措施。

LivenessProbe探針配置

示例一:經過exec方式作健康探測

exec-liveness.yaml  
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

在該配置文件中,對容器執行livenessProbe檢查,periodSeconds字段指定kubelet每5s執行一次檢查,檢查的命令爲cat /tmp/healthy,initialDelaySeconds字段告訴kubelet應該在執行第一次檢查以前等待5秒,
若是命令執行成功,則返回0,那麼kubelet就認爲容器是健康的,若是爲非0,則Kubelet會Kill掉容器並根據重啓策略來決定是否須要重啓。api

當容器啓動時,它會執行如下命令:服務器

/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"

對於容器的前30秒,有一個/tmp/healthy文件。所以,在前30秒內,該命令cat /tmp/healthy返回成功代碼。30秒後,cat /tmp/healthy返回失敗代碼。app

建立Pod:tcp

kubectl create -f https://k8s.io/examples/pods/probe/exec-liveness.yaml

在30秒內,查看Pod事件:ide

kubectl describe pod liveness-exec

輸出代表還沒有探測到失敗:spa

FirstSeen    LastSeen    Count   From            SubobjectPath           Type        Reason      Message
--------- --------    -----   ----            -------------           --------    ------      -------
24s       24s     1   {default-scheduler }                    Normal      Scheduled   Successfully assigned liveness-exec to worker0
23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulling     pulling image "k8s.gcr.io/busybox"
23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulled      Successfully pulled image "k8s.gcr.io/busybox"
23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Created     Created container with docker id 86849c15382e; Security:[seccomp=unconfined]
23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Started     Started container with docker id 86849c15382e

35秒後,再次查看Pod事件:code

kubectl describe pod liveness-exec

在輸出的中顯示探測失敗,而且容器已被殺死並從新建立。

FirstSeen LastSeen    Count   From            SubobjectPath           Type        Reason      Message
--------- --------    -----   ----            -------------           --------    ------      -------
37s       37s     1   {default-scheduler }                    Normal      Scheduled   Successfully assigned liveness-exec to worker0
36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulling     pulling image "k8s.gcr.io/busybox"
36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulled      Successfully pulled image "k8s.gcr.io/busybox"
36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Created     Created container with docker id 86849c15382e; Security:[seccomp=unconfined]
36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Started     Started container with docker id 86849c15382e
2s        2s      1   {kubelet worker0}   spec.containers{liveness}   Warning     Unhealthy   Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory

再等30秒,確認Container已從新啓動:

kubectl get pod liveness-exec

下面輸出中RESTARTS的次數已增長:

AME            READY     STATUS    RESTARTS   AGE
liveness-exec   1/1       Running   1          1m

示例二:經過HTTP方式作健康探測

pods/probe/http-liveness.yaml  
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/liveness
    args:
    - /server
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: X-Custom-Header
          value: Awesome
      initialDelaySeconds: 3
      periodSeconds: 3

在配置文件中,使用k8s.gcr.io/liveness鏡像,建立出一個Pod,其中periodSeconds字段指定kubelet每3秒執行一次探測,initialDelaySeconds字段告訴kubelet延遲等待3秒,探測方式爲向容器中運行的服務發送HTTP GET請求,請求8080端口下的/healthz, 任何大於或等於200且小於400的代碼表示成功。任何其餘代碼表示失敗。

建立此Pod

kubectl create -f https://k8s.io/examples/pods/probe/http-liveness.yaml

10秒後,查看Pod事件以驗證liveness探測失敗而且Container已從新啓動:

kubectl describe pod liveness-http

httpGet探測方式有以下可選的控制字段

  • host:要鏈接的主機名,默認爲Pod IP,能夠在http request head中設置host頭部。
  • scheme: 用於鏈接host的協議,默認爲HTTP。
  • path:http服務器上的訪問URI。
  • httpHeaders:自定義HTTP請求headers,HTTP容許重複headers。
  • port: 容器上要訪問端口號或名稱。

示例三:經過TCP方式作健康探測

Kubelet將嘗試在指定的端口上打開容器上的套接字,若是能創建鏈接,則代表容器健康。

pods/probe/tcp-liveness-readiness.yaml  
apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: k8s.gcr.io/goproxy:0.1
    ports:
    - containerPort: 8080
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

TCP檢查方式和HTTP檢查方式很是類似,示例中兩種探針都使用了,在容器啓動5秒後,kubelet將發送第一個readinessProbe探針,這將鏈接到容器的8080端口,若是探測成功,則該Pod將被標識爲ready,10秒後,kubelet將進行第二次鏈接。
除此以後,此配置還包含了livenessProbe探針,在容器啓動15秒後,kubelet將發送第一個livenessProbe探針,仍然嘗試鏈接容器的8080端口,若是鏈接失敗則重啓容器。
建立:

kubectl create -f https://k8s.io/examples/pods/probe/tcp-liveness-readiness.yaml

15秒後,查看Pod事件以驗證活動探測:

kubectl describe pod goproxy

當容器有多個端口時,一般會給每一個端口命名,因此在使用探針探測時,也能夠直接寫自定義的端口名稱

ports:
- name: liveness-port
  containerPort: 8080
  hostPort: 8080
livenessProbe:
  httpGet:
    path: /healthz
    port: liveness-port

ReadinessProbe探針配置:

ReadinessProbe探針的使用場景livenessProbe稍有不一樣,有的時候應用程序可能暫時沒法接受請求,好比Pod已經Running了,可是容器內應用程序還沒有啓動成功,在這種狀況下,若是沒有ReadinessProbe,則Kubernetes認爲它能夠處理請求了,然而此時,咱們知道程序還沒啓動成功是不能接收用戶請求的,因此不但願kubernetes把請求調度給它,則使用ReadinessProbe探針。
ReadinessProbe和livenessProbe可使用相同探測方式,只是對Pod的處置方式不一樣,ReadinessProbe是將Pod IP:Port從對應的EndPoint列表中刪除,而livenessProbe則Kill容器並根據Pod的重啓策略來決定做出對應的措施。
ReadinessProbe探針探測容器是否已準備就緒,若是未準備就緒則kubernetes不會將流量轉發給此Pod。

ReadinessProbe探針與livenessProbe同樣也支持exec、httpGet、TCP的探測方式,配置方式相同,只不過是將livenessProbe字段修改成ReadinessProbe。

readinessProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
  initialDelaySeconds: 5
  periodSeconds: 5

ReadinessProbe探針的HTTP、TCP的探測方式也與livenessProbe的基本一致。

示例四: ReadinessProbe示例

如今來看一個加入ReadinessProbe探針和一個沒有ReadinessProbe探針的示例:
該示例中,建立了一個deploy,名爲JavaApp,啓動的容器運行一個java應用程序,程序監聽端口爲8080。

# 沒有加入ReadinessProbe
cat JavaApp.yaml
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: JavaApp
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      test: JavaApp
  template: 
    metadata:
      labels:
         test: JavaApp
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: env
                operator: In
                values:
                - testing
      containers:
      - image: 192.168.1.183:8081/jar/JavaApp:29
        name: JavaApp
        ports:  
        - containerPort: 8080
      imagePullSecrets:
      - name: myregistrykey
---       
kind: Service
apiVersion: v1
metadata:
  name: JavaApp
  namespace: default
spec:
  selector:
      test: JavaApp
  ports:
    - protocol: TCP
      port: 8080

建立:

kubectl create -f JavaApp.yaml

剛建立後,等幾秒鐘後,查看Pod狀態:

$  kubectl get pod
NAME                     READY     STATUS    RESTARTS   AGE
JavaApp-579b45567c-tdsrk    1/1      Running        0            6s

從上面能夠看到,Pod剛啓動6s,自身狀態已Running,其READ字段,1/1 表示1個容器狀態已準備就緒了,此時,對於kubernetes而言,它已經能夠接收請求了,而實際上服務還沒法訪問,由於JAVA程序還尚啓動起來,本人實驗中的JAVA程序啓動時間大概須要50s,50s後方可正常訪問,因此針對此類程序,必須配置ReadinessProbe。

#加入readinessProbe
kind: Deployment
apiVersion: apps/v1
metadata:
  name: JavaApp
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      test: JavaApp
  template: 
    metadata:
      labels:
        test: JavaApp
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: env
                operator: In
                values:
                - testing
      containers:
      - image: 192.168.1.183:8081/jar/JavaApp:29
        name: JavaApp
        ports:  
        - containerPort: 8080
        readinessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 60
          periodSeconds: 10
      imagePullSecrets:
      - name: myregistrykey
---
kind: Service
apiVersion: v1
metadata:
  name: JavaApp
  namespace: default
spec:
  selector:
    test: JavaApp
  ports:
    - protocol: TCP
      port: 8080

在該配置文件中,ReadinessProbe探針的探測方式爲tcpSocket,由於程序監聽在8080端口,因此這裏探測爲對8080創建鏈接。程序啓動時間大概50多秒,因此這裏第一次探測時間是在Pod Runing後60秒後,間隔10秒後執行第二次探測。
建立Pod:

kubectl create -f JavaApp.yaml

建立後等50秒查看狀態:

$ kubectl get pod -o wide
NAME                         READY     STATUS    RESTARTS   AGE          IP             NODE
JavaApp-64b58cfd5c-kpc4s    0/1       Running   0           55s     172.26.91.109   192.168.1.180

Pod雖然已處於Runnig狀態,可是因爲第一次探測時間未到,因此READY字段爲0/1,即容器的狀態爲未準備就緒,在未準備就緒的狀況下,其Pod對應的Service下的Endpoint也爲空,因此纔不會有任何請求被調度進來。

$ kubectl get endpoints
   NAME           ENDPOINTS   
  JavaApp

當經過第一次探測的檢查經過後,容器的狀態天然會轉爲READ狀態。

$ kubectl get pod
NAME                      READY     STATUS    RESTARTS   AGE
JavaApp-64b58cfd5c-qj886   1/     Running       0          1m

$ kubectl get endpoints 
NAME                ENDPOINTS                          AGE
JavaApp            172.26.91.113:8080                 1m

此後根據指定的間隔時間10s後再次探測,若是不經過,則kubernetes就會將Pod IP從EndPoint列表中移除。

配置探針(Probe)相關屬性

探針(Probe)有許多可選字段,能夠用來更加精確的控制Liveness和Readiness兩種探針的行爲(Probe):

  • initialDelaySeconds:Pod啓動後延遲多久才進行檢查,單位:秒。
  • periodSeconds:檢查的間隔時間,默認爲10,單位:秒。
  • timeoutSeconds:探測的超時時間,默認爲1,單位:秒。
  • successThreshold:探測失敗後認爲成功的最小鏈接成功次數,默認爲1,在Liveness探針中必須爲1,最小值爲1。
  • failureThreshold:探測失敗的重試次數,重試必定次數後將認爲失敗,在readiness探針中,Pod會被標記爲未就緒,默認爲3,最小值爲1。
相關文章
相關標籤/搜索