1. 程式人生 > 其它 >k8s:容器生命週期回撥

k8s:容器生命週期回撥

原文:https://kubernetes.io/zh/docs/concepts/containers/container-lifecycle-hooks/

https://kubernetes.io/zh/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/

概述

類似於許多具有生命週期回撥元件的程式語言框架,例如 Angular、Kubernetes 為容器提供了生命週期回撥。 回撥使容器能夠了解其管理生命週期中的事件,並在執行相應的生命週期回撥時執行在處理程式中實現的程式碼。

容器回撥

有兩個回撥暴露給容器:

PostStart

這個回撥在容器被建立之後立即被執行。 但是,不能保證回撥會在容器入口點(ENTRYPOINT)之前執行。 沒有引數傳遞給處理程式。

PreStop

在容器因 API 請求或者管理事件(諸如存活態探針、啟動探針失敗、資源搶佔、資源競爭等) 而被終止之前,此回撥會被呼叫。 如果容器已經處於已終止或者已完成狀態,則對 preStop 回撥的呼叫將失敗。 在用來停止容器的 TERM 訊號被髮出之前,回撥必須執行結束。 Pod 的終止寬限週期在 PreStop 回撥被執行之前即開始計數,所以無論 回撥函式的執行結果如何,容器最終都會在 Pod 的終止寬限期內被終止。 沒有引數會被傳遞給處理程式。

回撥處理程式的實現

容器可以通過實現和註冊該回調的處理程式來訪問該回調。 針對容器,有兩種型別的回撥處理程式可供實現:

  • Exec - 在容器的 cgroups 和名稱空間中執行特定的命令(例如 pre-stop.sh
    )。 命令所消耗的資源計入容器的資源消耗。
  • HTTP - 對容器上的特定端點執行 HTTP 請求。

回撥處理程式執行

當呼叫容器生命週期管理回撥時,Kubernetes 管理系統根據回撥動作執行其處理程式, httpGettcpSocket 在kubelet 程序執行,而 exec 則由容器內執行 。

回撥處理程式呼叫在包含容器的 Pod 上下文中是同步的。 這意味著對於 PostStart 回撥,容器入口點和回撥非同步觸發。 但是,如果回撥執行或掛起的時間太長,則容器無法達到 running 狀態。

PreStop 回撥並不會與停止容器的訊號處理程式非同步執行;回撥必須在 可以傳送訊號之前完成執行。 如果 PreStop

回撥在執行期間停滯不前,Pod 的階段會變成 Terminating 並且一直處於該狀態,直到其 terminationGracePeriodSeconds 耗盡為止, 這時 Pod 會被殺死。 這一寬限期是針對 PreStop 回撥的執行時間及容器正常停止時間的總和而言的。 例如,如果 terminationGracePeriodSeconds 是 60,回撥函式花了 55 秒鐘 完成執行,而容器在收到訊號之後花了 10 秒鐘來正常結束,那麼容器會在其 能夠正常結束之前即被殺死,因為 terminationGracePeriodSeconds 的值 小於後面兩件事情所花費的總時間(55+10)。

如果 PostStartPreStop 回撥失敗,它會殺死容器。

使用者應該使他們的回撥處理程式儘可能的輕量級。 但也需要考慮長時間執行的命令也很有用的情況,比如在停止容器之前儲存狀態。

回撥遞送保證

回撥的遞送應該是 至少一次,這意味著對於任何給定的事件, 例如 PostStartPreStop,回撥可以被呼叫多次。 如何正確處理被多次呼叫的情況,是回撥實現所要考慮的問題。

通常情況下,只會進行單次遞送。 例如,如果 HTTP 回撥接收器宕機,無法接收流量,則不會嘗試重新發送。 然而,偶爾也會發生重複遞送的可能。 例如,如果 kubelet 在傳送回撥的過程中重新啟動,回撥可能會在 kubelet 恢復後重新發送。

實踐

定義 postStart 和 preStop 處理函式

下面是對應 Pod 的配置檔案:

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: nginx
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
      preStop:
        exec:
          command: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]

在上述配置檔案中,你可以看到 postStart 命令在容器的 /usr/share 目錄下寫入檔案 message。 命令 preStop 負責優雅地終止 nginx 服務。當因為失效而導致容器終止時,這一處理方式很有用。

建立 Pod:

kubectl apply -f https://k8s.io/examples/pods/lifecycle-events.yaml

驗證 Pod 中的容器已經執行:

kubectl get pod lifecycle-demo

使用 shell 連線到你的 Pod 裡的容器:

kubectl exec -it lifecycle-demo -- /bin/bash

在 shell 中,驗證 postStart 處理函式建立了 message 檔案:

root@lifecycle-demo:/# cat /usr/share/message

命令列輸出的是 postStart 處理函式所寫入的文字

Hello from the postStart handler

討論

Kubernetes 在容器建立後立即傳送 postStart 事件。 然而,postStart 處理函式的呼叫不保證早於容器的入口點(entrypoint) 的執行。postStart 處理函式與容器的程式碼是非同步執行的,但 Kubernetes 的容器管理邏輯會一直阻塞等待 postStart 處理函式執行完畢。 只有 postStart 處理函式執行完畢,容器的狀態才會變成 RUNNING。

Kubernetes 在容器結束前立即傳送 preStop 事件。除非 Pod 寬限期限超時,Kubernetes 的容器管理邏輯 會一直阻塞等待 preStop 處理函式執行完畢。