本文已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
Kubernetes 1.24:StatefulSet 的最大不可用副本數
Kubernetes StatefulSets 自 1.5 版本推出並在 1.9 版本中穩定以來,已廣泛用於運行具狀態應用程式。它們提供穩定的 Pod 身分、每個 Pod 持續性儲存和有序的優雅部署、擴展和滾動更新。您可以將 StatefulSet 視為運行複雜具狀態應用程式的原子構建模組。隨著 Kubernetes 的使用增加,需要 StatefulSet 的情境數量也隨之增加。在您針對 StatefulSet 使用 OrderedReady
Pod 管理策略的情況下,這些情境中有許多需要比目前支援的單次一個 Pod 更新更快的滾動更新。
以下是一些範例
我正在使用 StatefulSet 來協調多實例、基於快取的應用程式,其中快取的大小很大。快取啟動時是冷的,並且需要相當長的時間才能啟動容器。可能需要更多初始啟動任務。此 StatefulSet 上的 RollingUpdate 將花費大量時間才能完全更新應用程式。如果 StatefulSet 支援一次更新多個 Pod,則會產生更快的更新速度。
我的具狀態應用程式由領導者和追隨者或一個寫入器和多個讀取器組成。我有多個讀取器或追隨者,並且我的應用程式可以容忍多個 Pod 同時關閉。我希望一次更新此應用程式多個 Pod,以便更快地推出新更新,尤其是當我的應用程式實例數量很大時。請注意,我的應用程式仍然需要每個 Pod 的唯一身分。
為了支援此類情境,Kubernetes 1.24 包含一項新的 Alpha 功能來提供協助。在使用新功能之前,您必須啟用 MaxUnavailableStatefulSet
功能旗標。啟用後,您可以指定一個名為 maxUnavailable
的新欄位,它是 StatefulSet 的 spec
的一部分。例如
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
namespace: default
spec:
podManagementPolicy: OrderedReady # you must set OrderedReady
replicas: 5
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
# image changed since publication (previously used registry "k8s.gcr.io")
- image: registry.k8s.io/nginx-slim:0.8
imagePullPolicy: IfNotPresent
name: nginx
updateStrategy:
rollingUpdate:
maxUnavailable: 2 # this is the new alpha field, whose default value is 1
partition: 0
type: RollingUpdate
如果您啟用新功能,並且未在 StatefulSet 中為 maxUnavailable
指定值,則 Kubernetes 會套用預設值 maxUnavailable: 1
。這與您在未啟用新功能時看到的行為相符。
我將根據該範例資訊清單運行一個情境,以示範此功能的工作原理。我將部署一個具有 5 個副本的 StatefulSet,其中 maxUnavailable
設定為 2,partition
設定為 0。
我可以透過將映像變更為 registry.k8s.io/nginx-slim:0.9
來觸發滾動更新。一旦我啟動滾動更新,我就可以觀察到 Pod 一次更新 2 個,因為 maxUnavailable 的目前值為 2。以下輸出顯示了一段時間,但並不完整。maxUnavailable 可以是絕對數字 (例如 2) 或所需 Pod 的百分比 (例如 10%)。絕對數字是從百分比計算得出的,方法是四捨五入到最接近的整數。
kubectl get pods --watch
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 85s
web-1 1/1 Running 0 2m6s
web-2 1/1 Running 0 106s
web-3 1/1 Running 0 2m47s
web-4 1/1 Running 0 2m27s
web-4 1/1 Terminating 0 5m43s ----> start terminating 4
web-3 1/1 Terminating 0 6m3s ----> start terminating 3
web-3 0/1 Terminating 0 6m7s
web-3 0/1 Pending 0 0s
web-3 0/1 Pending 0 0s
web-4 0/1 Terminating 0 5m48s
web-4 0/1 Terminating 0 5m48s
web-3 0/1 ContainerCreating 0 2s
web-3 1/1 Running 0 2s
web-4 0/1 Pending 0 0s
web-4 0/1 Pending 0 0s
web-4 0/1 ContainerCreating 0 0s
web-4 1/1 Running 0 1s
web-2 1/1 Terminating 0 5m46s ----> start terminating 2 (only after both 4 and 3 are running)
web-1 1/1 Terminating 0 6m6s ----> start terminating 1
web-2 0/1 Terminating 0 5m47s
web-1 0/1 Terminating 0 6m7s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 ContainerCreating 0 1s
web-1 1/1 Running 0 2s
web-2 0/1 Pending 0 0s
web-2 0/1 Pending 0 0s
web-2 0/1 ContainerCreating 0 0s
web-2 1/1 Running 0 1s
web-0 1/1 Terminating 0 6m6s ----> start terminating 0 (only after 2 and 1 are running)
web-0 0/1 Terminating 0 6m7s
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
web-0 0/1 ContainerCreating 0 0s
web-0 1/1 Running 0 1s
請注意,一旦滾動更新開始,序數最高的兩個 Pod (4 和 3) 會同時開始終止。序號為 4 和 3 的 Pod 可能會以自己的速度準備就緒。一旦 Pod 4 和 3 都準備就緒,Pod 2 和 1 會同時開始終止。當 Pod 2 和 1 都正在運行且準備就緒時,Pod 0 開始終止。
在 Kubernetes 中,StatefulSet 的更新在更新 Pod 時遵循嚴格的順序。在此範例中,更新從副本 4 開始,然後是副本 3,然後是副本 2,依此類推,一次一個 Pod。當一次處理一個 Pod 時,3 不可能在 4 之前運行並準備就緒。當 maxUnavailable
大於 1 時 (在範例情境中,我將 maxUnavailable
設定為 2),副本 3 可能在副本 4 準備就緒之前就已準備就緒並運行,這是可以接受的。如果您是開發人員,並且將 maxUnavailable
設定為大於 1,則您應該知道此結果是可能的,並且您必須確保您的應用程式能夠處理如果發生的任何排序問題。當您將 maxUnavailable
設定為大於 1 時,將保證在每批更新的 Pod 之間保持順序。此保證表示,在批次 0 (副本 4 和 3) 中的 Pod 準備就緒之前,批次 2 (副本 2 和 1) 中的 Pod 無法開始更新。
儘管 Kubernetes 將這些稱為副本,但您的具狀態應用程式可能有不同的視圖,並且 StatefulSet 的每個 Pod 可能持有與其他 Pod 完全不同的資料。這裡重要的是,StatefulSet 的更新以批次方式進行,而您現在可以擁有大於 1 的批次大小 (作為 Alpha 功能)。
另請注意,上述行為適用於 podManagementPolicy: OrderedReady
。如果您將 StatefulSet 定義為 podManagementPolicy: Parallel
,則不僅 maxUnavailable
數量的副本會同時終止;maxUnavailable
數量的副本也會同時在 ContainerCreating
階段啟動。這稱為突發。
因此,現在您可能對以下內容有很多疑問:-
- 當您設定
podManagementPolicy: Parallel
時的行為是什麼? - 當
partition
設定為0
以外的值時的行為是什麼?
最好親自嘗試看看。這是一項 Alpha 功能,Kubernetes 貢獻者正在尋求有關此功能的意見回饋。這是否有助於您實現具狀態情境?您是否發現錯誤,或者您是否認為實作的行為不直觀,或者可能會破壞應用程式或讓它們措手不及?請開啟一個 issue 讓我們知道。