1. 程式人生 > 其它 >POD健康檢查--探針probe

POD健康檢查--探針probe

探針是由kubelet對容器執行的定期診斷

探針的三種規則:
livenessProbe :判斷容器是否正在執行。如果探測失敗,則kubelet會殺死容器,並且容器將根據 restartPolicy 來設定 Pod 狀態。如果容器不提供存活探針,則預設狀態為Success。

readinessProbe :判斷容器是否準備好接受請求。如果探測失敗,端點控制器將從與 Pod 匹配的所有 service endpoints 中剔除刪除該Pod的IP地址。初始延遲之前的就緒狀態預設為Failure。如果容器不提供就緒探針,則預設狀態為Success。

startupProbe(這個1.17版本增加的):判斷容器內的應用程式是否已啟動,主要針對於不能確定具體啟動時間的應用。如果配置了 startupProbe 探測,在則在 startupProbe 狀態為 Success 之前,其他所有探針都處於無效狀態,直到它成功後其他探針才起作用。 如果 startupProbe 失敗,kubelet 將殺死容器,容器將根據 restartPolicy 來重啟。如果容器沒有配置 startupProbe, 則預設狀態為 Success

注:以上規則可以同時定義。在readinessProbe檢測成功之前,Pod的running狀態是不會變成ready狀態的

Probe支援三種檢查方法:
exec :在容器內執行指定命令。如果命令退出時返回碼為0則認為診斷成功

tcpSocket :對指定埠上的容器的IP地址進行TCP檢查(三次握手)。如果埠開啟,則診斷被認為是成功的

httpGet :對指定的埠和路徑上的容器的IP地址執行HTTPGet請求。如果響應的狀態碼大於等於200且小於400,則診斷被認為是成功的

每次探測都將獲得以下三種結果之一:
●成功:容器通過了診斷。
●失敗:容器未通過診斷。
●未知:診斷失敗,因此不會採取任何行動

官網示例:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/

======示例1:exec方式======
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 60
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      failureThreshold: 1
      initialDelaySeconds: 5
      periodSeconds: 5

#initialDelaySeconds:指定 kubelet 在執行第一次探測前應該等待5秒,即第一次探測是在容器啟動後的第6秒才開始執行。預設是 0 秒,最小值是 0。
#periodSeconds:指定了 kubelet 應該每 5 秒執行一次存活探測。預設是 10 秒。最小值是 1。
#failureThreshold: 當探測失敗時,Kubernetes 將在放棄之前重試的次數。 存活探測情況下的放棄就意味著重新啟動容器。就緒探測情況下的放棄 Pod 會被打上未就緒的標籤。預設值是 3。最小值是 1。
#timeoutSeconds:探測的超時後等待多少秒。預設值是 1 秒。最小值是 1。(在 Kubernetes 1.20 版本之前,exec 探針會忽略 timeoutSeconds 探針會無限期地 持續執行,甚至可能超過所配置的限期,直到返回結果為止。)

vim exec.yaml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
  namespace: default
spec:
  containers:
  - name: liveness-exec-container
    image: busybox
    imagePullPolicy: IfNotPresent
    command: ["/bin/sh","-c","touch /tmp/live ; sleep 30; rm -rf /tmp/live; sleep 3600"]
    livenessProbe:
      exec:
        command: ["test","-e","/tmp/live"]
      initialDelaySeconds: 1
      periodSeconds: 3
	  
kubectl create -f exec.yaml

kubectl describe pods liveness-exec
Events:
  Type     Reason     Age               From               Message
  ----     ------     ----              ----               -------
  Normal   Scheduled  51s               default-scheduler  Successfully assigned default/liveness-exec-pod to node02
  Normal   Pulled     46s               kubelet, node02    Container image "busybox" already present on machine
  Normal   Created    46s               kubelet, node02    Created container liveness-exec-container
  Normal   Started    45s               kubelet, node02    Started container liveness-exec-container
  Warning  Unhealthy  8s (x3 over 14s)  kubelet, node02    Liveness probe failed:
  Normal   Killing    8s                kubelet, node02    Container liveness-exec-container failed liveness probe,will be restarted

kubectl get pods -w
NAME                READY   STATUS    RESTARTS   AGE
liveness-exec       1/1     Running   1          85s

可以看到 Pod 中只有一個容器。kubelet 在執行第一次探測前需要等待 5 秒,kubelet 會每 5 秒執行一次存活探測。kubelet 在容器內執行命令 cat /tmp/healthy 來進行探測。如果命令執行成功並且返回值為 0,kubelet 就會認為這個容器是健康存活的。 當到達第 31 秒時,這個命令返回非 0 值,kubelet 會殺死這個容器並重新啟動它

======示例2:httpGet方式======
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: Custom-Header
          value: Awesome
      initialDelaySeconds: 3
      periodSeconds: 3

在這個配置檔案中,可以看到 Pod 也只有一個容器。initialDelaySeconds 欄位告訴 kubelet 在執行第一次探測前應該等待 3 秒。periodSeconds 欄位指定了 kubelet 每隔 3 秒執行一次存活探測。kubelet 會向容器內執行的服務(服務會監聽 8080 埠)傳送一個 HTTP GET 
請求來執行探測。如果伺服器上 /healthz 路徑下的處理程式返回成功程式碼,則 kubelet 認為容器是健康存活的。如果處理程式返回失敗程式碼,則 kubelet 會殺死這個容器並且重新啟動它。 任何大於或等於 200 並且小於 400 的返回程式碼標示成功,其它返回程式碼都標示失敗。 vim httpget.yaml apiVersion: v1 kind: Pod metadata: name: liveness-httpget namespace: default spec: containers: - name: liveness-httpget-container image: soscscs/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 livenessProbe: httpGet: port: http path: /index.html initialDelaySeconds: 1 periodSeconds: 3 timeoutSeconds: 10 kubectl create -f httpget.yaml kubectl exec -it liveness-httpget -- rm -rf /usr/share/nginx/html/index.html kubectl get pods NAME READY STATUS RESTARTS AGE liveness-httpget 1/1 Running 1 2m44s
======示例3:tcpSocket方式======
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

這個例子同時使用 readinessProbe 和 livenessProbe 探測。kubelet 會在容器啟動 5 秒後傳送第一個 readinessProbe 探測。這會嘗試連線 goproxy 容器的 8080 埠。如果探測成功,kubelet 將繼續每隔 10 秒執行一次檢測。除了 readinessProbe 探測,這個配置包括
了一個 livenessProbe 探測。kubelet 會在容器啟動 15 秒後進行第一次 livenessProbe 探測。就像 readinessProbe 探測一樣,會嘗試連線 goproxy 容器的 8080 埠。如果 livenessProbe 探測失敗,這個容器會被重新啟動。 vim tcpsocket.yaml apiVersion: v1 kind: Pod metadata: name: probe-tcp spec: containers: - name: nginx image: soscscs/myapp:v1 livenessProbe: initialDelaySeconds: 5 timeoutSeconds: 1 tcpSocket: port: 8080 periodSeconds: 3 kubectl create -f tcpsocket.yaml kubectl exec -it probe-tcp -- netstat -natp Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1/nginx: master pro kubectl get pods -w NAME READY STATUS RESTARTS AGE probe-tcp 1/1 Running 0 4s probe-tcp 1/1 Running 1 14s probe-tcp 1/1 Running 2 26s
======示例4:就緒檢測======
vim readiness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
  name: readiness-httpget
  namespace: default
spec:
  containers:
  - name: readiness-httpget-container
    image: soscscs/myapp:v1
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    readinessProbe:
      httpGet:
        port: 80
        path: /index1.html
      initialDelaySeconds: 1
      periodSeconds: 3
    livenessProbe:
      httpGet:
        port: http
        path: /index.html
      initialDelaySeconds: 1
      periodSeconds: 3
      timeoutSeconds: 10

kubectl create -f readiness-httpget.yaml

//readiness探測失敗,無法進入READY狀態
kubectl get pods 
NAME                READY   STATUS    RESTARTS   AGE
readiness-httpget   0/1     Running   0          18s

kubectl exec -it readiness-httpget sh
 # cd /usr/share/nginx/html/
 # ls
50x.html    index.html
 # echo 123 > index1.html 
 # exit

kubectl get pods 
NAME                READY   STATUS    RESTARTS   AGE
readiness-httpget   1/1     Running   0          2m31s

kubectl exec -it readiness-httpget -- rm -rf /usr/share/nginx/html/index.html

kubectl get pods -w
NAME                READY   STATUS    RESTARTS   AGE
readiness-httpget   1/1     Running   0          4m10s
readiness-httpget   0/1     Running   1          4m15s
======示例5:就緒檢測2======
vim readiness-myapp.yaml
apiVersion: v1
kind: Pod
metadata:
  name: myapp1
  labels:
     app: myapp
spec:
  containers:
  - name: myapp
    image: soscscs/myapp:v1
    ports:
    - name: http
      containerPort: 80
    readinessProbe:
      httpGet:
        port: 80
        path: /index.html
      initialDelaySeconds: 5
      periodSeconds: 5
      timeoutSeconds: 10 
---
apiVersion: v1
kind: Pod
metadata:
  name: myapp2
  labels:
     app: myapp
spec:
  containers:
  - name: myapp
    image: soscscs/myapp:v1
    ports:
    - name: http
      containerPort: 80
    readinessProbe:
      httpGet:
        port: 80
        path: /index.html
      initialDelaySeconds: 5
      periodSeconds: 5
      timeoutSeconds: 10 
---
apiVersion: v1
kind: Pod
metadata:
  name: myapp3
  labels:
     app: myapp
spec:
  containers:
  - name: myapp
    image: soscscs/myapp:v1
    ports:
    - name: http
      containerPort: 80
    readinessProbe:
      httpGet:
        port: 80
        path: /index.html
      initialDelaySeconds: 5
      periodSeconds: 5
      timeoutSeconds: 10 
---
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
  type: ClusterIP
  ports:
  - name: http
    port: 80
    targetPort: 80

kubectl create -f readiness-myapp.yaml

kubectl get pods,svc,endpoints -o wide
NAME         READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
pod/myapp1   1/1     Running   0          3m42s   10.244.2.13   node02   <none>           <none>
pod/myapp2   1/1     Running   0          3m42s   10.244.1.15   node01   <none>           <none>
pod/myapp3   1/1     Running   0          3m42s   10.244.2.14   node02   <none>           <none>

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE     SELECTOR
......
service/myapp        ClusterIP   10.96.138.13   <none>        80/TCP    3m42s   app=myapp

NAME                   ENDPOINTS                                      AGE
......
endpoints/myapp        10.244.1.15:80,10.244.2.13:80,10.244.2.14:80   3m42s


kubectl exec -it pod/myapp1 -- rm -rf /usr/share/nginx/html/index.html

//readiness探測失敗,Pod 無法進入READY狀態,且端點控制器將從 endpoints 中剔除刪除該 Pod 的 IP 地址
kubectl get pods,svc,endpoints -o wide
NAME         READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
pod/myapp1   0/1     Running   0          5m17s   10.244.2.13   node02   <none>           <none>
pod/myapp2   1/1     Running   0          5m17s   10.244.1.15   node01   <none>           <none>
pod/myapp3   1/1     Running   0          5m17s   10.244.2.14   node02   <none>           <none>

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE     SELECTOR
......
service/myapp        ClusterIP   10.96.138.13   <none>        80/TCP    5m17s   app=myapp

NAME                   ENDPOINTS                       AGE
......
endpoints/myapp        10.244.1.15:80,10.244.2.14:80   5m17s
======啟動、退出動作======
vim post.yaml
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: soscscs/myapp:v1
    lifecycle:   #此為關鍵欄位
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler >> /var/log/nginx/message"]      
      preStop:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the poststop handler >> /var/log/nginx/message"]
    volumeMounts:
    - name: message-log
      mountPath: /var/log/nginx/
      readOnly: false
  initContainers:
  - name: init-myservice
    image: soscscs/myapp:v1
    command: ["/bin/sh", "-c", "echo 'Hello initContainers'   >> /var/log/nginx/message"]
    volumeMounts:
    - name: message-log
      mountPath: /var/log/nginx/
      readOnly: false
  volumes:
  - name: message-log
    hostPath:
      path: /data/volumes/nginx/log/
      type: DirectoryOrCreate

kubectl create -f post.yaml

kubectl get pods -o wide
NAME             READY   STATUS    RESTARTS   AGE    IP            NODE     NOMINATED NODE   READINESS GATES
lifecycle-demo   1/1     Running   0          2m8s   10.244.2.28   node02   <none>           <none>

kubectl exec -it lifecycle-demo -- cat /var/log/nginx/message
Hello initContainers
Hello from the postStart handler

//在 node02 節點上檢視
[root@node02 ~]# cd /data/volumes/nginx/log/
[root@node02 log]# ls
access.log  error.log  message
[root@node02 log]# cat message 
Hello initContainers
Hello from the postStart handler
#由上可知,init Container先執行,然後當一個主容器啟動後,Kubernetes 將立即傳送 postStart 事件。

//刪除 pod 後,再在 node02 節點上檢視
kubectl delete pod lifecycle-demo

[root@node02 log]# cat message 
Hello initContainers
Hello from the postStart handler
Hello from the poststop handler
#由上可知,當在容器被終結之前, Kubernetes 將傳送一個 preStop 事件。