中斷事件

本指南適用於想要建置高可用性應用程式的應用程式擁有者,因此需要了解 Pod 可能發生的中斷事件類型。

本指南也適用於想要執行自動化叢集動作的叢集管理員,例如升級與自動擴展叢集。

自願與非自願中斷事件

Pod 在有人(人員或控制器)摧毀它們之前,或發生不可避免的硬體或系統軟體錯誤之前,不會消失。

我們將這些不可避免的情況稱為應用程式的非自願中斷事件。範例包括

  • 節點後端實體機器的硬體故障
  • 叢集管理員錯誤刪除 VM (執行個體)
  • 雲端提供者或 Hypervisor 故障導致 VM 消失
  • 核心 panic
  • 節點因叢集網路分割而從叢集中消失
  • 由於節點資源不足而驅逐 Pod。

除了資源不足的情況外,所有這些情況對大多數使用者來說應該都很熟悉;它們並非 Kubernetes 特有。

我們將其他情況稱為自願中斷事件。這些包括應用程式擁有者啟動的動作以及叢集管理員啟動的動作。典型的應用程式擁有者動作包括

  • 刪除管理 Pod 的部署或其他控制器
  • 更新部署的 Pod 範本導致重新啟動
  • 直接刪除 Pod (例如,不小心)

叢集管理員的動作包括

  • 排空節點以進行修復或升級。
  • 從叢集中排空節點以縮減叢集規模 (瞭解叢集自動擴展)。
  • 從節點移除 Pod,以便在該節點上容納其他物件。

這些動作可能由叢集管理員直接執行,或由叢集管理員執行的自動化程序執行,或由您的叢集託管供應商執行。

詢問您的叢集管理員或查閱您的雲端供應商或發行版本文件,以確定您的叢集是否啟用任何自願性中斷來源。 如果沒有啟用任何來源,您可以跳過建立 Pod 中斷預算。

處理中斷

以下是一些減輕非自願性中斷的方法

  • 確保您的 Pod 請求其所需的資源。
  • 如果您需要更高的可用性,請複製您的應用程式。(瞭解執行複製的無狀態有狀態應用程式。)
  • 為了在執行複製應用程式時獲得更高的可用性,請將應用程式分散在機架之間 (使用反親和性) 或跨區域 (如果使用多區域叢集)。

自願性中斷的頻率各不相同。 在基本的 Kubernetes 叢集上,沒有自動化的自願性中斷 (只有使用者觸發的中斷)。 然而,您的叢集管理員或託管供應商可能會執行一些額外的服務,這些服務會導致自願性中斷。 例如,推出節點軟體更新可能會導致自願性中斷。 此外,叢集 (節點) 自動擴展的某些實作可能會導致自願性中斷,以整理碎片和壓縮節點。 您的叢集管理員或託管供應商應記錄預期會發生的自願性中斷程度 (如果有的話)。 某些組態選項,例如在您的 Pod 規格中使用 PriorityClasses,也可能導致自願性 (和非自願性) 中斷。

Pod 中斷預算

功能狀態: Kubernetes v1.21 [stable]

Kubernetes 提供功能,即使您引入頻繁的自願性中斷,也能協助您執行高可用性的應用程式。

作為應用程式擁有者,您可以為每個應用程式建立 PodDisruptionBudget (PDB)。 PDB 限制了因自願性中斷而同時關閉的複寫應用程式的 Pod 數量。 例如,基於仲裁的應用程式會希望確保正在執行的複本數量永遠不會低於仲裁所需的數量。 Web 前端可能會希望確保服務負載的複本數量永遠不會低於總數的特定百分比。

叢集管理員和託管供應商應使用尊重 Pod 中斷預算的工具,方法是呼叫驅逐 API,而不是直接刪除 Pod 或部署。

例如,kubectl drain 子命令可讓您將節點標記為停止服務。 當您執行 kubectl drain 時,該工具會嘗試驅逐您要停止服務的節點上的所有 Pod。 kubectl 代表您提交的驅逐請求可能會暫時被拒絕,因此該工具會定期重試所有失敗的請求,直到目標節點上的所有 Pod 都終止,或直到達到可組態的逾時。

PDB 指定應用程式可以容忍的複本數量,相對於它預期擁有的數量。 例如,.spec.replicas: 5 的 Deployment 應該在任何給定時間有 5 個 Pod。 如果其 PDB 允許一次有 4 個,則驅逐 API 將允許一次自願性中斷一個 (而不是兩個) Pod。

組成應用程式的 Pod 群組是使用標籤選取器指定的,與應用程式的控制器 (deployment、stateful-set 等) 使用的標籤選取器相同。

「預期」的 Pod 數量是從管理這些 Pod 的工作負載資源的 .spec.replicas 計算出來的。 控制平面透過檢查 Pod 的 .metadata.ownerReferences 來發現擁有的工作負載資源。

非自願性中斷無法透過 PDB 預防;但是它們會計入預算。

由於應用程式的滾動升級而刪除或無法使用的 Pod 會計入中斷預算,但是當執行滾動升級時,工作負載資源 (例如 Deployment 和 StatefulSet) 不受 PDB 的限制。 相反地,應用程式更新期間的故障處理是在特定工作負載資源的規格中組態的。

建議將 AlwaysAllow 不健康 Pod 驅逐策略設定為您的 Pod 中斷預算,以支援在節點排空期間驅逐行為異常的應用程式。 預設行為是等待應用程式 Pod 變成健康狀態,然後才能繼續排空。

當使用驅逐 API 驅逐 Pod 時,它會優雅地終止,並遵循其 PodSpec 中的 terminationGracePeriodSeconds 設定。

Pod 中斷預算範例

考慮一個具有 3 個節點的叢集,node-1node-3。 叢集正在執行多個應用程式。 其中一個應用程式有 3 個複本,最初稱為 pod-apod-bpod-c。 另一個不相關的 Pod,沒有 PDB,稱為 pod-x,也顯示出來。 最初,Pod 的佈局如下

node-1node-2node-3
pod-a 可用pod-b 可用pod-c 可用
pod-x 可用

所有 3 個 Pod 都是部署的一部分,並且它們共同具有一個 PDB,該 PDB 要求始終至少有 3 個 Pod 中的 2 個可用。

例如,假設叢集管理員想要重新啟動到新的核心版本,以修正核心中的錯誤。 叢集管理員首先嘗試使用 kubectl drain 命令排空 node-1。 該工具嘗試驅逐 pod-apod-x。 這立即成功。 兩個 Pod 同時進入 terminating 狀態。 這使叢集處於此狀態

node-1 排空中node-2node-3
pod-a 終止中pod-b 可用pod-c 可用
pod-x 終止中

部署注意到其中一個 Pod 正在終止,因此它建立一個名為 pod-d 的替換 Pod。 由於 node-1 已被隔離,因此它會落在另一個節點上。 某個東西也建立了 pod-y 作為 pod-x 的替換 Pod。

(注意:對於 StatefulSet,pod-a,它會被稱為類似 pod-0 的名稱,需要完全終止,然後才能建立其替換 Pod,該替換 Pod 也稱為 pod-0,但具有不同的 UID。 否則,此範例也適用於 StatefulSet。)

現在叢集處於此狀態

node-1 排空中node-2node-3
pod-a 終止中pod-b 可用pod-c 可用
pod-x 終止中pod-d 啟動中pod-y

在某個時間點,Pod 終止,並且叢集看起來像這樣

node-1 已排空node-2node-3
pod-b 可用pod-c 可用
pod-d 啟動中pod-y

此時,如果一位不耐煩的叢集管理員嘗試排空 node-2node-3,則排空命令將會封鎖,因為部署只有 2 個可用的 Pod,而其 PDB 要求至少有 2 個。經過一段時間後,pod-d 變為可用。

現在叢集狀態看起來像這樣

node-1 已排空node-2node-3
pod-b 可用pod-c 可用
pod-d 可用pod-y

現在,叢集管理員嘗試排空 node-2。 排空命令將嘗試以某種順序驅逐兩個 Pod,例如先驅逐 pod-b,然後驅逐 pod-d。 它將成功驅逐 pod-b。 但是,當它嘗試驅逐 pod-d 時,將會被拒絕,因為這將僅為部署留下一個可用的 Pod。

部署為 pod-b 建立一個名為 pod-e 的替換 Pod。 因為叢集中沒有足夠的資源來排程 pod-e,所以排空將再次封鎖。 叢集最終可能會處於此狀態

node-1 已排空node-2node-3無節點
pod-b 終止中pod-c 可用pod-e 等待中
pod-d 可用pod-y

此時,叢集管理員需要將節點新增回叢集,才能繼續進行升級。

您可以看到 Kubernetes 如何根據以下因素改變中斷發生的速率

  • 應用程式需要多少複本
  • 優雅關閉執行個體需要多長時間
  • 啟動新執行個體需要多長時間
  • 控制器的類型
  • 叢集的資源容量

Pod 中斷條件

功能狀態: Kubernetes v1.31 [stable] (預設啟用:true)

新增了專用的 Pod DisruptionTarget condition,以指示 Pod 即將因中斷而刪除。 條件的 reason 欄位另外指示 Pod 終止的以下原因之一

PreemptionByScheduler
Pod 即將被排程器搶佔,以便容納具有更高優先順序的新 Pod。 如需更多資訊,請參閱Pod 優先順序搶佔
DeletionByTaintManager
Pod 即將被 Taint Manager (它是 kube-controller-manager 內節點生命週期控制器的一部分) 刪除,因為 Pod 不容忍 NoExecute 污點; 請參閱基於 污點的驅逐。
EvictionByEvictionAPI
Pod 已被標記為使用 Kubernetes API 驅逐
DeletionByPodGC
繫結到不再存在的節點的 Pod,即將被 Pod 垃圾收集刪除。
TerminationByKubelet
Pod 已被 kubelet 終止,原因可能是節點壓力驅逐優雅節點關閉,或為系統關鍵 Pod 進行搶佔。

在所有其他中斷情境中,例如由於超出 Pod 容器限制而導致的驅逐,Pod 不會收到 DisruptionTarget 條件,因為中斷可能是由 Pod 引起的,並且會在重試時再次發生。

除了清理 Pod 之外,Pod 垃圾收集器 (PodGC) 也會將處於非終止階段的 Pod 標記為失敗 (另請參閱 Pod 垃圾收集)。

當使用 Job (或 CronJob) 時,您可能會想要使用這些 Pod 中斷條件作為 Job Pod 失敗策略的一部分。

區分叢集擁有者和應用程式擁有者角色

通常,將叢集管理員和應用程式擁有者視為彼此了解有限的獨立角色很有用。 這種責任劃分在以下情境中可能很有意義

  • 當許多應用程式團隊共用一個 Kubernetes 叢集,並且存在自然的角色專業分工時
  • 當使用第三方工具或服務來自動化叢集管理時

Pod 中斷預算透過在角色之間提供介面來支援這種角色劃分。

如果您的組織中沒有這種責任劃分,您可能不需要使用 Pod 中斷預算。

如何在您的叢集上執行破壞性動作

如果您是叢集管理員,並且需要在叢集中的所有節點上執行破壞性動作,例如節點或系統軟體升級,以下是一些選項

  • 在升級期間接受停機時間。
  • 容錯移轉到另一個完整的複本叢集。
    • 沒有停機時間,但對於重複的節點和協調切換的人力而言,都可能成本高昂。
  • 編寫容忍中斷的應用程式並使用 PDB。
    • 沒有停機時間。
    • 最小的資源重複。
    • 允許更多叢集管理自動化。
    • 編寫容忍中斷的應用程式很棘手,但是容忍自願性中斷的工作與支援自動擴展和容忍非自願性中斷的工作在很大程度上重疊。

下一步

上次修改時間:2024 年 8 月 7 日上午 9:11 PST:新增註解,說明 DisruptionTarget 的情境必須可重試 (a68cedecee)