OpenKruise V1.4 版本解讀:新增 Job Sidecar Terminator 能力

阿里云云原生發表於2023-04-24

作者:立衡

前言

OpenKruise 是阿里雲開源的雲原生應用自動化管理套件,也是當前託管在 Cloud Native Computing Foundation (CNCF) 下的孵化專案。它來自阿里巴巴多年來容器化、雲原生的技術沉澱,是阿里內部生產環境大規模應用的基於 Kubernetes 之上的標準擴充套件元件,也是緊貼上游社群標準、適應網際網路規模化場景的技術理念與最佳實踐。

OpenKruise:

https://github.com/openkruise/kruise

OpenKruise 在 2023.3.31 釋出了最新的 v1.4 版本(ChangeLog [ 1] ),新增 Job Sidecar Terminator 重磅功能,本文將對新版本做整體的概覽介紹。

01 重要更新

  • 為了方便大家使用 Kruise 增強能力,預設開啟了一些穩定的能力,如下:ResourcesDeletionProtection,WorkloadSpread,PodUnavailableBudgetDeleteGate,InPlaceUpdateEnvFromMetadata, StatefulSetAutoDeletePVC,PodProbeMarkerGate。上述能力大部分是需要特別配置才會生效的,所以預設開啟一般不會對存量叢集造成影響,如果有一些特性不想使用,可以在升級時關閉。
  • Kruise-Manager leader 選舉方式從 configmaps 遷移為 configmapsleases,為後面遷移到 leases 方式做準備,另外,這是官方提供的平滑升級的方式,不會對存量的叢集造成影響。

02 Sidecar 容器管理能力:Job Sidecar Terminator

在 Kubernetes 中對於 Job 型別 Workload,人們通常希望當主容器完成任務並退出後,Pod 進入已完成狀態。然而,當這些 Pod 擁有 Long-Running Sidecar 容器時,由於 Sidecar 容器在主容器退出後無法自行退出,導致 Pod 一直無法進入已完成狀態。

面對這個問題,社群的常見解決方案一般都需要對 Main 和 Sidecar 進行改造,兩者透過 Volume 共享來實現 Main 容器退出之後,Sidecar 容器完成退出的效果。

社群的解決方案可以解決這個問題,但是需要對容器進行改造,尤其對於社群通用的 Sidecar 容器,改造和維護的成本太高了。

為此,我們在 Kruise 中加入了一個名為 SidecarTerminator 的控制器,專門用於在此類場景下,監聽主容器的完成狀態,並選擇合適的時機終止掉 Pod 中的 sidecar 容器,並且無需對 Main 和 Sidecar 容器進行侵入式改造。

執行在普通節點的 Pod

對於執行於普通節點的 Pod(常規 Kubelet),使用該特性非常簡單,使用者只需要在要在目標 sidecar 容器中新增一個特殊的 env 對其進行標識,控制器會在恰當的時機利用 Kruise Daemon 提供的 CRR 的能力,將這些 sidecar 容器終止:

kind: Job
spec:
  template:
    spec:
      containers:
        - name: sidecar
          env:
            - name: KRUISE_TERMINATE_SIDECAR_WHEN_JOB_EXIT
              value: "true"
        - name: main
... ...

執行在虛擬節點的 Pod

對於一些提供 Serverless 容器的平臺,例如 ECI [ 2]  或者 Fargate [ 3] ,其 Pods 只能執行於 Virtual-Kubelet [ 4]  之類的虛擬節點。然而,Kruise Daemon 無法部署和工作在這些虛擬節點之上,導致無法使用 CRR 能力將容器終止。但幸運地是,我們可以藉助原生 Kubernetes 提供的 Pod 原地升級機制來達到同樣的目的:只需要構造一個特殊映象,這個映象的唯一作用就是當被拉起後,會快速地主動退出,這樣一來,只需要在退出 sidecar 時,將原本的 sidecar 映象替換為快速退出映象,即可達到退出 sidecar 的目的。

步驟一:準備一個快速退出映象

  • 該映象只需要具備非常簡單的邏輯:當其被拉起後,直接退出,且退出碼為 0。
  • 該映象需要相容原 sidecar 映象的 commands 和 args,以防容器被拉起時報錯。

步驟二:配置你的 sidecar 容器

kind: Job
spec:
  template:
    spec:
      containers:
        - name: sidecar
          env:
            - name: KRUISE_TERMINATE_SIDECAR_WHEN_JOB_EXIT_WITH_IMAGE
              value: "example/quick-exit:v1.0.0"
        - name: main
... ...

使用你自己準備的快速退出映象來替換上述 "example/quick-exit:v1.0.0".

注意事項

  • sidecar 容器必須能夠響應 SIGTERM 訊號,並且當收到此訊號時,entrypoint 程式需要退出(即 sidecar 容器需要退出),並且退出碼應當為 0。
  • 該特性適用於任意 Job 型別 Workload 所管理的 Pod,只要他們的 RestartPolicy 為 Never/OnFailure 即可。
  • 具有環境變數 KRUISE_TERMINATE_SIDECAR_WHEN_JOB_EXIT 的容器將被視為 sidecar 容器,其他容器將被視為主容器,當所有主容器完成後,sidecar 容器才會被終止:

<!---->

    • 在 Never 重啟策略下,主容器一旦退出,將被視為"已完成"。
    • 在 OnFailure 重啟策略下,主容器退出程式碼必須為0,才會被視為"已完成"。

03 增強版本的工作負載

CloneSet 最佳化效能 :新增 FeatureGate CloneSetEventHandlerOptimization

當前,無論是 Pod 的狀態變化還是 Metadata 變化,Pod Update 事件都會觸發 CloneSet reconcile 邏輯。CloneSet Reconcile 預設配置了三個 worker,對於叢集規模較小的場景,這種情況並不會造成問題。

但對於叢集規模較大或 Pod Update 事件較多的情況,這些無效的 reconcile 將會阻塞真正的 CloneSet reconcile,進而導致 CloneSet 的滾動升級等變更延遲。為了解決這個問題,可以開啟 feature-gate CloneSetEventHandlerOptimization 來減少一些不必要的 reconcile 入隊。

CloneSet 新增 disablePVCReuse 欄位

如果一個 Pod 被外部直接呼叫刪除或驅逐時,這個 Pod 關聯的 PVCs 還都存在;並且 CloneSet controller 發現數量不足重新擴容時,新擴出來的 Pod 會複用原 Pod 的 instance-id 並關聯原來的 PVCs。

然而,如果 Pod 所在的 Node 出現異常,複用可能會導致新 Pod 啟動失敗,詳情參考 issue 1099 [ 5] 。為了解決這個問題,您可以設定欄位 disablePVCReuse=true,當 Pod 被驅逐或者刪除後,與 Pod 相關的 PVCs 將被自動刪除,不再被複用。

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
  ...
  replicas: 4
  scaleStrategy:
    disablePVCReuse: true

CloneSet 增加 PreNormal 生命週期鉤子

CloneSet 已經支援了 PreparingUpdate、PreparingDelete 兩種生命週期鉤子,用於應用的優雅下線,詳情參考社群文件 [ 6] 。為了支援優雅上線的場景,本次新增加了 PreNormal 狀態,具體如下:

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
  # define with finalizer
  lifecycle:
    preNormal:
      finalizersHandler:
      - example.io/unready-blocker

  # or define with label
  lifecycle:
    preNormal:
      labelsHandler:
        example.io/block-unready: "true"

當 CloneSet 建立一個 Pod(包括正常擴容和重建升級)時:

  • 如果 Pod 滿足了 PreNormal hook 的定義,才會被認為是 Available,並且才會進入 Normal 狀態

這對於一些 Pod 建立時的後置檢查很有用,比如你可以檢查 Pod 是否已經掛載到 SLB 後端,從而避免滾動升級時,舊例項銷燬後,新例項掛載失敗導致的流量損失。

04 高階的應用運維能力

容器重啟新增 forceRecreate 欄位

當建立 CRR 資源時,如果容器正在啟動過程中,CRR 將不會再重啟容器。如果您想要強制重啟容器,可以使用以下欄位開啟:

apiVersion: apps.kruise.io/v1alpha1
kind: ContainerRecreateRequest
spec:
  ...
  strategy:
    forceRecreate: true

映象預熱支援 Attach metadata into cri interface

當 Kubelet 建立 Pod 時,Kubelet 將會 attach metadata 到 container runtime cri 介面。映象倉庫可以根據這些 metadata 資訊來確定拉映象的來源業務,如果發生了倉庫過載、壓力過大的情況,可以對具體的業務進行降級處理。OpenKruise 映象預熱同樣支援類似的能力,如下:

apiVersion: apps.kruise.io/v1alpha1
kind: ImagePullJob
spec:
  ...
  image: nginx:1.9.1
  sandboxConfig:
    annotations:
      io.kubernetes.image.metrics.tags: "cluster=cn-shanghai"
    labels:
      io.kubernetes.image.app: "foo"

社群參與

非常歡迎你透過 Github/Slack/釘釘/微信 等方式加入我們來參與 OpenKruise 開源社群。你是否已經有一些希望與我們社群交流的內容呢?可以在我們的社群雙週會 [7 ] 上分享你的聲音,或透過以下渠道參與討論:

  • 加入社群 Slack channel [ 8] (English)
  • 加入社群釘釘群:搜尋群號 23330762 (Chinese)
  • 加入社群微信群(新):新增使用者 openkruise 並讓機器人拉你入群 (Chinese)

相關連結:

[1] ChangeLog

https://github.com/openkruise/kruise/blob/master/CHANGELOG.md

[2] ECI

https://www.aliyun.com/product/eci

[3] Fargate

https://aws.amazon.com/cn/fargate/

[4] Virtual-Kubelet

https://virtual-kubelet.io/#:~:text=Virtual%20Kubelet%20is%20an%20open,as%20serverless%20cloud%20container%20platforms.

[5] issue 1099

https://github.com/openkruise/kruise/issues/1099

[6] 社群文件

https://openkruise.io/docs/user-manuals/cloneset/#lifecycle-hook

[7] 社群雙週會

https://browser.alibaba-inc.com/?Url=https://shimo.im/docs/gX...

[8] Slack channel

https://kubernetes.slack.com/?redir=%2Farchives%2Fopenkruise

點選此處,檢視 OpenKruise 專案官方主頁與文件

相關文章