作者:立衡
前言
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/gXqmeQOYBehZ4vqo
[8] Slack channel
https://kubernetes.slack.com/?redir=%2Farchives%2Fopenkruise
點擊此處,查看 OpenKruise 項目官方主頁與文檔