為應用程式指定中斷預算
Kubernetes v1.21 [stable]
本頁面展示瞭如何限制應用程式所經歷的併發中斷次數,從而在允許叢集管理員管理叢集節點的同時,提高應用程式的可用性。
準備工作
你的 Kubernetes 伺服器版本必須是 v1.21 或更高。要檢查版本,請輸入 kubectl version
。
- 你是執行在 Kubernetes 叢集上、需要高可用性應用程式的所有者。
- 你應該知道如何部署可複製的無狀態應用程式和/或可複製的有狀態應用程式。
- 你應該已經閱讀過有關Pod 中斷的內容。
- 你應該向叢集所有者或服務提供商確認他們是否遵循 Pod 中斷預算。
使用 PodDisruptionBudget 保護應用程式
- 識別你想使用 PodDisruptionBudget (PDB) 保護的應用程式。
- 思考你的應用程式如何應對中斷。
- 建立一個 YAML 檔案的 PDB 定義。
- 從 YAML 檔案建立 PDB 物件。
識別要保護的應用程式
最常見的用例是,你想保護由內建 Kubernetes 控制器之一指定的應用程式。
- 部署
- 複製控制器
- 副本集
- StatefulSet
在這種情況下,記下控制器的 .spec.selector
;同樣的 Selector 也將用於 PDB 的 .spec.selector
。
從版本 1.15 開始,PDB 支援啟用了擴縮子資源的自定義控制器。
你也可以將 PDB 與不受上述控制器控制的 Pod 或任意 Pod 組一起使用,但有一些限制,請參閱任意工作負載和任意選擇器。
思考你的應用程式如何應對中斷
決定在由於自願中斷而導致的短時間內,可以同時有多少個例項停機。
- 無狀態前端
- 問題:不要將服務容量減少超過 10%。
- 解決方案:例如,使用 PDB 並設定 minAvailable 為 90%。
- 問題:不要將服務容量減少超過 10%。
- 單例項有狀態應用程式
- 問題:未經我同意,請勿終止此應用程式。
- 可能解決方案 1:不使用 PDB 並容忍偶爾的停機時間。
- 可能解決方案 2:設定 PDB 並設定 maxUnavailable=0。達成一項(在 Kubernetes 之外的)協議,即叢集操作員在終止前需要諮詢你。當叢集操作員聯絡你時,準備停機,然後刪除 PDB 以表示已準備好中斷。之後重新建立。
- 問題:未經我同意,請勿終止此應用程式。
- 多例項有狀態應用程式,例如 Consul、ZooKeeper 或 etcd
- 問題:不要將例項數量減少到仲裁以下,否則寫入將失敗。
- 可能解決方案 1:將 maxUnavailable 設定為 1(適用於不同規模的應用程式)。
- 可能解決方案 2:將 minAvailable 設定為仲裁大小(例如,當規模為 5 時設定為 3)。 (允許更多中斷同時發生)。
- 問題:不要將例項數量減少到仲裁以下,否則寫入將失敗。
- 可重啟的批處理作業
- 問題:作業在自願中斷時需要完成。
- 可能解決方案:不建立 PDB。Job 控制器將建立一個替換 Pod。
- 問題:作業在自願中斷時需要完成。
指定百分比時的舍入邏輯
minAvailable
或 maxUnavailable
的值可以表示為整數或百分比。
- 當你指定一個整數時,它表示 Pod 的數量。例如,如果你將
minAvailable
設定為 10,那麼即使在中斷期間,也必須始終有 10 個 Pod 可用。 - 當你透過將值設定為百分比的字串表示(例如
"50%"
)來指定百分比時,它表示總 Pod 的百分比。例如,如果你將minAvailable
設定為"50%"
,那麼在中斷期間,至少有 50% 的 Pod 保持可用。
當你將值指定為百分比時,它可能無法對映到精確的 Pod 數量。例如,如果你有 7 個 Pod 並將 minAvailable
設定為 "50%"
,那麼這意味著必須有 3 個 Pod 還是 4 個 Pod 可用,這並不立即顯而易見。Kubernetes 會向上舍入到最接近的整數,因此在這種情況下,必須有 4 個 Pod 可用。當你將 maxUnavailable
值指定為百分比時,Kubernetes 會向上舍入可能被中斷的 Pod 數量。因此,中斷可能會超過你定義的 maxUnavailable
百分比。你可以檢視控制此行為的程式碼。
指定 PodDisruptionBudget
PodDisruptionBudget
有三個欄位
- 一個標籤選擇器
.spec.selector
,用於指定它適用的 Pod 集合。此欄位是必需的。 .spec.minAvailable
,描述了從該集合中在驅逐後仍必須可用的 Pod 數量,即使沒有被驅逐的 Pod。minAvailable
可以是絕對數量或百分比。.spec.maxUnavailable
(在 Kubernetes 1.7 及更高版本中可用),描述了從該集合中在驅逐後可以不可用的 Pod 數量。它可以是絕對數量或百分比。
注意
對於 PodDisruptionBudgets 的 policy/v1beta1 和 policy/v1 API,空選擇器的行為不同。對於 policy/v1beta1,空選擇器匹配零個 Pod,而對於 policy/v1,空選擇器匹配名稱空間中的所有 Pod。在一個 PodDisruptionBudget
中,你只能指定 maxUnavailable
和 minAvailable
中的一個。maxUnavailable
只能用於控制擁有關聯控制器管理的 Pod 的驅逐。在下面的示例中,“所需副本數”是管理由 PodDisruptionBudget
選擇的 Pod 的控制器的 scale
。
示例 1:當 minAvailable
為 5 時,只要 PodDisruptionBudget 的 selector
所選的 Pod 中,剩餘 健康的 Pod 數量為 5 個或更多,就允許驅逐。
示例 2:當 minAvailable
為 30% 時,只要所需副本總數的至少 30% 是健康的,就允許驅逐。
示例 3:當 maxUnavailable
為 5 時,只要所需副本總數中不健康的副本數量最多為 5 個,就允許驅逐。
示例 4:當 maxUnavailable
為 30% 時,只要不健康副本的數量不超過所需副本總數的 30%(向上取整到最接近的整數),就允許驅逐。如果所需副本總數只有一個,則該單個副本仍然允許中斷,導致有效不可用性達到 100%。
在典型用法中,一個預算將用於由控制器管理的 Pod 集合——例如,單個 ReplicaSet 或 StatefulSet 中的 Pod。
注意
中斷預算並不能真正保證指定數量/百分比的 Pod 將始終處於執行狀態。例如,當集合達到預算中指定的最小大小時,託管該集合中 Pod 的節點可能會發生故障,從而導致該集合中可用 Pod 的數量低於指定大小。預算只能防止自願驅逐,而不是所有不可用原因。如果你將 maxUnavailable
設定為 0% 或 0,或者將 minAvailable
設定為 100% 或副本數,則你要求零自願驅逐。當你為一個工作負載物件(例如 ReplicaSet)設定零自願驅逐時,你將無法成功排空執行其中一個 Pod 的節點。如果你嘗試排空一個執行不可驅逐 Pod 的節點,排空將永遠無法完成。這符合 PodDisruptionBudget
的語義,是被允許的。
你可以在下面找到定義的 Pod 中斷預算示例。它們匹配帶有標籤 app: zookeeper
的 Pod。
使用 minAvailable 的 PDB 示例
使用 maxUnavailable 的 PDB 示例
例如,如果上述 zk-pdb
物件選擇大小為 3 的 StatefulSet 中的 Pod,則這兩個規範具有完全相同的含義。建議使用 maxUnavailable
,因為它會自動響應相應控制器副本數的變化。
建立 PDB 物件
你可以使用 kubectl 建立或更新 PDB 物件。
kubectl apply -f mypdb.yaml
檢查 PDB 的狀態
使用 kubectl 檢查你的 PDB 是否已建立。
假設你的名稱空間中實際上沒有匹配 app: zookeeper
的 Pod,那麼你會看到類似這樣的內容
kubectl get poddisruptionbudgets
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
zk-pdb 2 N/A 0 7s
如果有匹配的 Pod(例如 3 個),那麼你會看到類似這樣的內容
kubectl get poddisruptionbudgets
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
zk-pdb 2 N/A 1 7s
ALLOWED DISRUPTIONS
的非零值表示中斷控制器已經看到了 Pod,計算了匹配的 Pod,並更新了 PDB 的狀態。
你可以使用此命令獲取有關 PDB 狀態的更多資訊
kubectl get poddisruptionbudgets zk-pdb -o yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
annotations:
…
creationTimestamp: "2020-03-04T04:22:56Z"
generation: 1
name: zk-pdb
…
status:
currentHealthy: 3
desiredHealthy: 2
disruptionsAllowed: 1
expectedPods: 3
observedGeneration: 1
Pod 的健康狀態
當前的實現將健康的 Pod 視為 .status.conditions
項中 type="Ready"
和 status="True"
的 Pod。這些 Pod 透過 PDB 狀態中的 .status.currentHealthy
欄位進行跟蹤。
不健康 Pod 的驅逐策略
Kubernetes v1.31 [stable]
(預設啟用:true)保護應用程式的 PodDisruptionBudget 確保透過不允許驅逐健康的 Pod,使 .status.currentHealthy
的 Pod 數量不會低於 .status.desiredHealthy
中指定的數量。透過使用 .spec.unhealthyPodEvictionPolicy
,你還可以定義何時應考慮驅逐不健康 Pod 的標準。未指定策略時的預設行為對應於 IfHealthyBudget
策略。
策略
IfHealthyBudget
- 正在執行 (
.status.phase="Running"
) 但尚未健康的 Pod 只有在受保護的應用程式未中斷 (.status.currentHealthy
至少等於.status.desiredHealthy
) 時才能被驅逐。 此策略確保已中斷應用程式中正在執行的 Pod 有最佳機會變得健康。這對於排空節點具有負面影響,因為它們可能被受 PDB 保護的行為異常應用程式(例如,由於錯誤或配置錯誤而處於
CrashLoopBackOff
狀態的 Pod,或未能報告Ready
狀況的 Pod)阻塞。AlwaysAllow
- 正在執行 (
.status.phase="Running"
) 但尚未健康的 Pod 被視為已中斷,無論 PDB 中的標準是否滿足,都可以被驅逐。 這意味著中斷應用程式中預期執行的 Pod 可能沒有機會變得健康。透過使用此策略,叢集管理員可以輕鬆驅逐受 PDB 保護的行為異常應用程式。更具體地說,是由於 bug 或配置錯誤而處於
CrashLoopBackOff
狀態的應用程式,或者只是未能報告Ready
狀況的 Pod。
注意
處於Pending
、Succeeded
或 Failed
階段的 Pod 總是被考慮驅逐。任意工作負載和任意選擇器
如果你只將 PDB 與內建工作負載資源(Deployment、ReplicaSet、StatefulSet 和 ReplicationController)或實現 scale
子資源的自定義資源一起使用,並且 PDB 選擇器與 Pod 的擁有資源的選擇器完全匹配,則可以跳過此部分。
你可以將 PDB 與由其他資源、"運算子" 或裸 Pod 控制的 Pod 一起使用,但有以下限制:
- 只能使用
.spec.minAvailable
,不能使用.spec.maxUnavailable
。 .spec.minAvailable
只能使用整數值,不能使用百分比。
無法使用其他可用性配置,因為 Kubernetes 在沒有受支援的擁有資源的情況下無法派生 Pod 的總數。
你可以使用選擇器來選擇屬於工作負載資源的 Pod 的子集或超集。驅逐 API 將不允許驅逐被多個 PDB 覆蓋的任何 Pod,因此大多數使用者會希望避免重疊的選擇器。重疊 PDB 的一個合理用途是在 Pod 從一個 PDB 轉換到另一個 PDB 時。