Kubernetes Container lifecycle hooks

簡介

在kubernetes中,容器hooks旨在解決服務進程啟動與停止時的一些優雅操作需求。比如說進程停止時要給進程一個清理數據的時間,保證服務的請求正常結束,而不是強行中斷服務的運行,這樣在生產環境中可能會造成不優雅的結果。
截止kubernetes v1.20版本,實現了PostStart和PreStop兩種容器hooks。
如果hooks執行失敗,容器將會被kill。
容器hooks由kubelet組件管理並啟動執行。

名詞解釋

hook 鉤子,軟體行業中指程式中在某一個地方定義的預留介面,而介面的實現可以後續指定。

容器Hooks介紹

  1. PostStart
    PostStart hook在容器啟動的時候運行,但並不保證該hook一定會比容器指定的ENTRYPOINT命令先運行。就是說PostStart和ENTRYPOINT都會在容器啟動後運行,至於誰先運行,誰先結束,並不一定,是隨機的。如果容器啟動的時候,PostStart沒有成功,容器不會處於running狀態。

  2. PreStop
    PreStop會在kubelet給Pod發送TERM訊號之前執行。一般API Server會給kubelet發送結束Pod的訊號,或者Pod的liveness/startup探針失敗,或其它原因導致Pod失敗,kubelet會嘗試發送TERM訊號給Pod里主進程。如果PreStop存在,kubelet則會優先啟動PreStop,待PreStop結束之後再發送TERM訊號給Pod。但從API Server將Pod標記為Terminating狀態開始,整個Pod停止時間不能超過terminationGracePeriodSeconds所設置的時間,如果超過,kubelet需要發送KILL訊號給Pod所有的進程。

舉例:
如果一個Pod設置terminationGracePeriodSeconds=60,PreStop執行需要55s,服務進程停止需要10s。API Server首先將需要停止的Pod標記為Terminating狀態,並且開始計算terminationGracePeriodSeconds時間。kubelet開始啟動PreStop,等待55s後執行完畢,kubelet給Pod的主進程發送TERM訊號,這時主進程開始清理退出,5s之後,terminationGracePeriodSeconds時間到達,kubelet將發送KILL訊號給Pod所有進程,強制停止。這一通操作之後,發現主服務進程沒有清理完畢就被強制停止了。面對這種情況,我們需要增加terminationGracePeriodSeconds=65。

Hooks類型

Exec 指定一個可執行命令或腳本,在容器內執行
HTTP 發送一個http請求給容器,由kubelet發送請求

Hooks執行的次數

hook至少會調用一次,意思說如果有多個觸發事件,hooks可能會被調用多次。
一般情況下hooks只會調用一次,只在很少的異常時候才會調用多次。比如在Pod停止的過程中kubelet被重啟,重啟後的kubelet會再次發送hooks調用。

Debug Hooks

PostStart執行失敗時會記錄FailedPostStartHook事件,PreStop執行失敗時會記錄FailedPreStopHook事件。可以通過kubectl describe pod <pod_name>查看。

容器Hooks配置示例

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"]