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