OpenKruise v1.3:新增自定義 Pod Probe 探針能力與大規模叢集效能顯著提升
作者:趙明山(立衡)
雲原生應用自動化管理套件、CNCF Sandbox 專案——OpenKruise,近期釋出了 v1.3 版本。
OpenKruise 是針對 Kubernetes 的增強能力套件,聚焦於雲原生應用的部署、升級、運維、穩定性防護等領域。
所有的功能都通過 CRD 等標準方式擴充套件,可以適用於 1.16 以上版本的任意 Kubernetes 叢集。單條 helm 命令即可完成 Kruise 的一鍵部署,無需更多配置。
版本解析
在版本 v1.3 中,OpenKruise 提供了新的 CRD 資源 PodProbeMarker,改善了大規模叢集的一些效能問題,Advanced DaemonSet 支援映象預熱,以及 CloneSet、WorkloadSpread、Advanced CronJob、SidecarSet 一些新的特性。
新增 CRD 和 Controller:PodProbeMarker
Kubernetes 提供了三種預設的 Pod 生命週期管理:
-
Readiness Probe:用來判斷業務容器是否已經準備好響應使用者請求,如果檢查失敗,會將該 Pod 從 Service Endpoints 中剔除。
-
Liveness Probe:用來判斷容器的健康狀態,如果檢查失敗,kubelet 將會重啟該容器。
-
Startup Probe:用來判斷容器是否啟動完成,如果定義了該 Probe,那麼 Readiness Probe 與 Liveness Probe 將會在它成功之後再執行。
所以 Kubernetes 中提供的 Probe 能力都已經限定了特定的語義以及相關的行為。除此之外,其實還是存在自定義 Probe 語義以及相關行為的需求,例如:
-
GameServer 定義 Idle Probe 用來判斷該 Pod 當前是否存在遊戲對局,如果沒有,從成本優化的角度,可以將該 Pod 縮容掉。
-
K8s Operator 定義 main-secondary Probe 來判斷當前 Pod 的角色(main or secondary) ,升級的時候,可以優先升級 secondary,進而達到升級過程只有一次選主的行為,降低升級過程中服務抖動時間。
OpenKruise 提供了自定義 Probe 的能力,並將結果返回到 Pod Status 中,使用者可以根據該結果決定後續的行為。
PodProbeMarker 配置如下:
apiVersion: apps.kruise.io/v1alpha1
kind: PodProbeMarker
metadata:
name: game-server-probe
namespace: ns
spec:
selector:
matchLabels:
app: game-server
probes:
- name: Idle
containerName: game-server
probe:
exec: /home/game/idle.sh
initialDelaySeconds: 10
timeoutSeconds: 3
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
markerPolicy:
- state: Succeeded
labels:
gameserver-idle: 'true'
annotations:
controller.kubernetes.io/pod-deletion-cost: '-10'
- state: Failed
labels:
gameserver-idle: 'false'
annotations:
controller.kubernetes.io/pod-deletion-cost: '10'
podConditionType: game.io/idle
PodProbeMarker 結果可以通過 Pod 物件檢視:
apiVersion: v1
kind: Pod
metadata:
labels:
app: game-server
gameserver-idle: 'true'
annotations:
controller.kubernetes.io/pod-deletion-cost: '-10'
name: game-server-58cb9f5688-7sbd8
namespace: ns
spec:
...
status:
conditions:
# podConditionType
- type: game.io/idle
# Probe State 'Succeeded' indicates 'True', and 'Failed' indicates 'False'
status: "True"
lastProbeTime: "2022-09-09T07:13:04Z"
lastTransitionTime: "2022-09-09T07:13:04Z"
# If the probe fails to execute, the message is stderr
message: ""
效能優化:大規模叢集效能顯著提升
-
1026 [ 1] 引入了延遲入隊機制,大幅優化了在大規模應用叢集下 kruise-manager 拉起時的 CloneSet 控制器工作佇列堆積問題,在理想情況下初始化時間減少了 80% 以上。
-
1027 [ 2] 優化 PodUnavailableBudget 控制器 Event Handler 邏輯,減少無關 Pod 入隊數量。
-
1011 [ 3] 通過快取機制,優化了大規模叢集下 Advanced DaemonSet 重複模擬 Pod 排程計算的 CPU、Memory 消耗。
-
1015 [ 4] , #1068 [ 5] 大幅降低了大規模叢集下的執行時記憶體消耗。彌補了 v1.1 版本中 Disable DeepCopy 的一些疏漏點,減少 expressions 型別 label selector 的轉換消耗。
SidecarSet 支援注入特定的歷史版本
SidecarSet 通過 ControllerRevision 記錄了關於 containers、volumes、initContainers、imagePullSecrets 和 patchPodMetadata 等欄位的歷史版本,並允許使用者在 Pod 建立時選擇特定的歷史版本進行注入。
基於這一特性,使用者可以規避在 SidecarSet 灰度釋出時,因 Deployment 等 Workload 擴容、升級等操作帶來的 SidecarSet 釋出風險。如果不選擇注入版本,SidecarSet 將對重建 Pod 預設全都注入最新版本 Sidecar。
SidecarSet 相關 ControllerRevision 資源被放置在了與 Kruise-Manager 相同的名稱空間中,使用者可以使用以下命令來檢視:
kubectl get controllerrvisions -n kruise-system -l kruise.io/sidecarset-name=your-sidecarset-name
此外,使用者還可以通過 SidecarSet 的 status.latestRevision 欄位看到當前版本對應的 ControllerRevision 名稱,以方便自行記錄。
1. 通過 ControllerRevision 名稱指定注入的 Sidecar 版本
apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: sidecarset
spec:
...
injectionStrategy:
revisionName: specific-controllerRevision-name
2. 通過自定義版本標識指定注入的 Sidecar 版本
使用者可以通過在發版時,同時給 SidecarSet 打上 apps.kruise.io/sidecarset-custom-version=your-version-id 來標記每一個歷史版本,SidecarSet 會將這個 label 向下帶入到對應的 ControllerRevision 物件,以便使用者進行篩選,並且允許使用者在選擇注入歷史版本時,使用改 your-version-id 來進行描述。
假設使用者只想灰度 10% 的 Pods 到 version-2,並且對於新建立的 Pod 希望都注入更加穩定的 version-1 版本來控制灰度風險:
apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: sidecarset
labels:
apps.kruise.io/sidecarset-custom-version: version-2
spec:
...
updateStrategy:
partition: 90%
injectionStrategy:
customVersion: version-1
SidecarSet 支援注入 Pod Annotations
SidecarSet 支援注入 Pod Annotations,配置如下:
apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
spec:
containers:
...
patchPodMetadata:
- annotations:
oom-score: '{"log-agent": 1}'
custom.example.com/sidecar-configuration: '{"command": "/home/admin/bin/start.sh", "log-level": "3"}'
patchPolicy: MergePatchJson
- annotations:
apps.kruise.io/container-launch-priority: Ordered
patchPolicy: Overwrite | Retain
patchPolicy 為注入的策略,如下:
-
Retain:預設策略,如果 Pod 中存在 annotation[key]=value ,則保留 Pod 原有的 value。只有當 Pod 中不存在 annotation[key] 時,才注入 annotations[key]=value。
-
Overwrite:與 Retain 對應,當 Pod 中存在 annotation[key]=value,將被強制覆蓋為 value2。
-
MergePatchJson:與 Overwrite 對應,annotations value為 json 字串。如果 Pod 不存在該 annotations[key],則直接注入。如果存在,則進行 json value 合併。例如:Pod 中存在 annotations[oom-score]='{"main": 2}',注入後將 value json 合併為 annotations[oom-score]='{"log-agent": 1, "main": 2}'。
注意:patchPolicy 為 Overwrite和MergePatchJson 時,SidecarSet 原地升級 Sidecar Container 時,能夠同步更新該 annotations。但是,如果只修改 annotations 則不能生效,只能搭配 Sidecar 容器映象一起原地升級。
patchPolicy 為 Retain 時,SidecarSet 原地升級 Sidecar Container 時,將不會同步更新該 annotations。
上述配置後,SidecarSet 在注入 Sidecar Container時,會注入 Pod annotations,如下:
apiVersion: v1
kind: Pod
metadata:
annotations:
apps.kruise.io/container-launch-priority: Ordered
oom-score: '{"log-agent": 1, "main": 2}'
custom.example.com/sidecar-configuration: '{"command": "/home/admin/bin/start.sh", "log-level": "3"}'
name: test-pod
spec:
containers:
...
注意:SidecarSet 從許可權、安全的考慮不應該注入或修改除 Sidecar Container 之外的 Pod 欄位,所以如果想要使用該能力,首先需要配置 SidecarSet_PatchPodMetadata_WhiteList 白名單或通過如下方式關閉白名單校驗:
helm install kruise https://... --set featureGates="SidecarSetPatchPodMetadataDefaultsAllowed =true"
Advanced DaemonSet 支援映象預熱
如果你在安裝或升級 Kruise 的時候啟用了 PreDownloadImageForDaemonSetUpdate feature-gate,DaemonSet 控制器會自動在所有舊版本 pod 所在 node 節點上預熱你正在灰度釋出的新版本映象。這對於應用釋出加速很有幫助。
預設情況下 DaemonSet 每個新映象預熱時的併發度都是 1,也就是一個個節點拉映象。
如果需要調整,你可以通過 apps.kruise.io/image-predownload-parallelism annotation 來設定併發度。
apiVersion: apps.kruise.io/v1alpha1
kind: DaemonSet
metadata:
annotations:
apps.kruise.io/image-predownload-parallelism: "10"
CloneSet 擴縮容與 PreparingDelete
預設情況下,CloneSet 將處於 PreparingDelete 狀態的 Pod 視為正常,意味著這些 Pod 仍然被計算在 replicas 數量中。
在這種情況下:
-
如果你將 replicas 從 N 改為 N-1,當一個要刪除的 Pod 還在 PreparingDelete 狀態中時,你重新將 replicas 改為 N,CloneSet 會將這個 Pod 重新置為 Normal 狀態。
-
如果你將 replicas 從 N 改為 N-1 的同時在 podsToDelete 中設定了一個 Pod,當這個 Pod 還在 PreparingDelete 狀態中時,你重新將 replicas 改為 N,CloneSet 會等到這個 Pod 真正進入 terminating 之後再擴容一個 Pod 出來。
-
如果你在不改變 replicas 的時候指定刪除一個 Pod,當這個 Pod 還在 PreparingDelete 狀態中時,CloneSet 會等到這個 Pod 真正進入 terminating 之後再擴容一個 Pod 出來。
從 Kruise v1.3.0 版本開始,你可以在 CloneSet 中設定一個 apps.kruise.io/cloneset-scaling-exclude-preparing-delete: "true" 標籤,它標誌著這個 CloneSet 不會將 PreparingDelete 狀態的 Pod 計算在 replicas 數量中。
在這種情況下:
-
如果你將 replicas 從 N 改為 N-1,當一個要刪除的 Pod 還在 PreparingDelete 狀態中時,你重新將 replicas 改為 N,CloneSet 會將這個 Pod 重新置為 Normal 狀態。
-
如果你將 replicas 從 N 改為 N-1 的同時在 podsToDelete 中設定了一個 Pod,當這個 Pod 還在 PreparingDelete 狀態中時,你重新將 replicas 改為 N,CloneSet 會立即建立一個新 Pod。
-
如果你在不改變 replicas 的時候指定刪除一個 Pod,當這個 Pod 還在 PreparingDelete 狀態中時,CloneSet 會立即建立一個新 Pod。
Advanced CronJob Time zones
預設情況下,所有 AdvancedCronJob schedule 排程時,都是基於 kruise-controller-manager 容器本地的時區所計算的。
不過,在 v1.3.0 版本中我們引入了 spec.timeZone 欄位,你可以將它設定為任意合法時區的名字。例如,設定 spec.timeZone: "Asia/Shanghai" 則 Kruise 會根據國內的時區計算 schedule 任務觸發時間。
Go 標準庫中內建了時區資料庫,作為在容器的系統環境中沒有外接資料庫時的 fallback 選擇。
其他改動
你可以通過 Github release [ 6] 頁面,來檢視更多的改動以及它們的作者與提交記錄。
社群參與
非常歡迎你通過 Github/Slack/釘釘/微信 等方式加入我們來參與 OpenKruise 開源社群。
你是否已經有一些希望與我們社群交流的內容呢?
可以在我們的社群雙週會上分享你的聲音,或通過以下渠道參與討論:
- 加入社群 Slack channel [ 7] (English)
- 加入社群釘釘群:搜尋群號 23330762 (Chinese)
- 加入社群微信群(新):新增使用者 openkruise 並讓機器人拉你入群 (Chinese)
參考連結
[1] #1026
https://github.com/openkruise/kruise/pull/1026
[2] #1027
https://github.com/openkruise/kruise/pull/1027
[3] #1011
https://github.com/openkruise/kruise/pull/1011
[4] #1015
https://github.com/openkruise/kruise/pull/1015
[5] #1068
https://github.com/openkruise/kruise/pull/1068
[6] Github release:
*https://github.com/openkruise */kruise/releases
[7] Slack channel:
https://kubernetes.slack.com/channels/openkruise
戳此處,檢視 OpenKruise 專案官方主頁與文件!
- 從 JDK 9 到 19,我們幫您提煉了和雲原生場景有關的能力列表(上)
- 統一觀測丨如何使用Prometheus 實現效能壓測指標可觀測
- CNStack 2.0:雲原生的技術中臺
- 全景剖析阿里雲容器網路資料鏈路(五):Terway ENI-Trunking
- 全景剖析阿里雲容器網路資料鏈路(四):Terway IPVLAN EBPF
- 全景剖析阿里雲容器網路資料鏈路(三):Terway ENIIP
- 談談我工作中的23個設計模式
- 雲邊協同下的統一應用管理:基於 OpenYurt 和 KubeVela 的解決方案
- OpenKruise v1.3:新增自定義 Pod Probe 探針能力與大規模叢集效能顯著提升
- Koordinator v0.7: 為任務排程領域注入新活力
- 傳統大型國企雲原生轉型,如何解決彈性、運維和團隊協同等問題
- Dubbo 3 易用性升級之 Dubbo 官網大改版
- 阿里雲容器服務 ACK 產品技術動態(202208)
- RocketMQ Streams在雲安全及 IoT 場景下的大規模最佳實踐
- RocketMQ 5.0:無狀態代理模式的探索與實踐
- Apache RocketMQ 5.0 在Stream場景的儲存增強
- 快手 RocketMQ 高效能實踐
- RocketMQ DLedger架構在小米的大規模實踐
- 定時任務報警通知解決方案詳解
- Dubbo Mesh 總體技術架構方案