1. 程式人生 > 其它 >Kubernetes Pod Hook

Kubernetes Pod Hook

在生產環境中使用spring框架,由於服務更新過程中,容器服務被直接停止,部分請求仍被分發到終止的容器(沒有配置鉤子,熟悉預設環境),導致服務出現500錯誤,這部分錯誤請求資料佔用比較少,因為Pod滾動更新都是一對一。因為部分使用者會產生伺服器錯誤的情況,考慮使用優雅的終止方式,將錯誤請求降到最低,直至滾動更新不影響使用者

首先我們先簡單的分析一下"優雅的停止Pod"

優雅停止(Graceful shutdown)這個說法來自於作業系統,比如我們windows關機系統首先會退出軟體然後一步步到達關機,而相對的就是硬終止(Hard shutdown),簡單的理解就是直接拔電源

到了微服務中,閘道器會把流量分配給每個Pod節點上,比如我們上線更新Pod的時候

  • 如果我們直接將Pod殺死,那這部分流量就無法得到正確處理,會影響部分使用者,通常來說閘道器或者註冊中心會將我們的服務保持一個心跳,過了心跳超時之後會自動摘除我們的服務,但是有一個問題就是超時時間可能是30秒也可能是60秒,雖然不會影響我們的系統,但是會產生使用者輕微抖動。
  • 如果我們在停止前執行一條命令,通知閘道器或者註冊中心這臺主機進行下線,那麼註冊中心就會標記這臺主機已經下線,不進行流量轉發,使用者就不會有任何影響,這就是優雅停止,將滾動更新影響最小化

Pod Hook

Pod Hook是由kubelet發起的,當容器中的程序啟動前或者容器中的程序終止之前執行,這是包含在容器的生命週期之中。我們可以同時為Pod中的所有容器都配置hook

在k8s中,理想的狀態是pod優雅釋放,併產生新的Pod。但是並不是每一個Pod都會這麼順利

  • Pod卡死,處理不了優雅退出的命令或者操作
  • 優雅退出的邏輯有BUG,陷入死迴圈
  • 程式碼問題,導致執行的命令沒有效果

對於以上問題,k8s的Pod終止流程中還有一個"最多可以容忍的時間",即grace period (在pod的.spec.terminationGracePeriodSeconds欄位定義),這個值預設是30秒,當我們執行kubectl delete的時候也可以通過--grace-period引數顯示指定一個優雅退出時間來覆蓋Pod中的配置,如果我們配置的grace period超過時間之後,k8s就只能選擇強制kill Pod

Kubernetes等待指定的時間稱為優雅終止寬限期。預設情況下,這是30秒。值得注意的是,這與preStop Hook和SIGTERM訊號並行發生。Kubernetes不會等待preStop Hook完成。如果你的應用程式完成關閉並在terminationGracePeriod完成之前退出,Kubernetes會立即進入下一步。

如果您的Pod通常需要超過30秒才能關閉,請確保增加優雅終止寬限期(通過terminationGracePeriodSeconds來實現)

Kubernetes為我們提供了兩種鉤子函式:

  • PostStart :這個鉤子在容器建立後立即執行。但是,並不能保證鉤子將在容器ENTRYPOINT之前執行,因為沒有引數傳遞給處理程式。 主要用於資源部署、環境準備等。不過需要注意的是如果鉤子花費時間過長以及於不能執行或者掛起,容器將不能達到Running狀態。

  • PreStop :鉤子在容器終止前立即被呼叫。它是阻塞的,意味著它是同步的,所以它必須在刪除容器的調用出發之前完成。主要用於優雅關閉應用程式、通知其他系統等。如果鉤子在執行期間掛起,Pod階段將停留在Running狀態並且不會達到failed狀態

如果PostStart或者PreStop鉤子失敗,它會殺死容器。所以我們應該讓鉤子函式儘可能的輕量。當然有些情況下,長時間執行命令是合理的,比如在停止容器之前預先保留狀態。

這裡稍微簡單說一下Pod終止的過程

  • 使用者傳送命令刪除Pod,Pod進入Terminating狀態
  • service摘除Pod節點
  • 當kubelet看到Pod已被標記終止,開始執行preStop鉤子,假如preStop hook的執行時間超過了grace period,kubelet會發送SIGTERM並等2秒

官方文件介紹

在Pod Hook鉤子函式中有Exec和HTTP兩種方式

  • Exec - 用於執行一段特定的命令,不過要注意的是該命令小號的資源會被計入容器

建立容器後,Kubernetes立即傳送postStart事件。但是,不能保證在呼叫Container的入口點之前先呼叫postStart處理程式。postStart處理程式相對於Container的程式碼非同步執行,但是Kubernetes對容器的管理會阻塞,直到postStart處理程式完成。在postStart處理程式完成之前,容器的狀態不會設定為RUNNING。

  • HTTP - 對容器上的特定端點執行HTTP請求

總結: Hook呼叫的日誌沒有暴露給Pod的Event,所以只能到通過describe命令來獲取,如果是正常的操作是不會有event,如果有錯誤可以看到FailedPostStartHook和FailedPreStopHook這種event。並且如果Hook調用出現錯誤,則Pod狀態不會是Running

簡單的說Kubernetes終止生命週期的每一步

  • Pod 設定為Terminating狀態,並從所有服務的Endpoints列表中刪除
  • 此時,Pod停止停止,但是Pod中執行的容器不受影響
  • PreStop Hook被執行
  • preStop Hook傳送容器特殊命令或者Http請求到Pod中,Pod應用程式在接收到SIGTERM(該SIGTERM訊號是用於導致程式終止的通用訊號。不同於SIGKILL,該訊號可以被阻止,處理和忽略。這是禮貌地要求程式終止的正常方法),如果使用第三方程式碼或者管理系統無法控制,則preStop Hook是在不修改應用程式的情況下觸發
  • SIGTERM訊號傳送給Pod
  • 此時,Kubernetes將向Pod中的容器傳送SIGTERM訊號,這個訊號即通知容器他們很快將進行關閉。
  • Kubernetes等待優雅的終止
  • 此時,Kubernetes等待指定的時間稱為優雅終止寬限期。預設情況下,這是30秒(可以修改),值得注意的是,PreStop Hook和SIGTREM資訊是屬於並行執行,Kubernetes不會等待PreStop Hook完成。

如果Pod在terminationGracePeriod完成之前推出,Kubernetes將進如釋放階段,如果容器在優雅終止寬限期(terminationGracePeriod限定時間),則會發送SIGKILL訊號並強制刪除。與此同時,所有的Kubernetes物件也會被清除