中斷

本指南適用於希望構建高可用應用程式,因此需要了解 Pod 可能發生何種中斷的應用程式所有者。

它也適用於希望執行自動化叢集操作(如升級和自動擴縮叢集)的叢集管理員。

自願中斷和非自願中斷

Pod 不會消失,除非有人(使用者或控制器)將其銷燬,或者發生無法避免的硬體或系統軟體錯誤。

我們將這些不可避免的情況稱為應用程式的 非自願中斷。例如:

  • 支援節點的物理機硬體故障
  • 叢集管理員錯誤刪除虛擬機器(例項)
  • 雲提供商或虛擬機器管理程式故障導致虛擬機器消失
  • 核心崩潰
  • 由於叢集網路分割槽,節點從叢集中消失
  • 由於節點 資源不足 導致 Pod 被驅逐。

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

我們將其他情況稱為 自願中斷。這包括應用程式所有者啟動的操作和叢集管理員啟動的操作。典型的應用程式所有者操作包括:

  • 刪除管理 Pod 的 Deployment 或其他控制器
  • 更新 Deployment 的 Pod 模板導致重啟
  • 直接刪除 Pod(例如意外刪除)

叢集管理員操作包括:

  • 排空節點 以進行修復或升級。
  • 從叢集中排空節點以縮減叢集(瞭解 節點自動擴縮)。
  • 從節點中刪除 Pod,以允許其他內容適合該節點。

這些操作可能由叢集管理員直接執行,也可能由叢集管理員執行的自動化程式執行,或者由你的叢集託管提供商執行。

請諮詢你的叢集管理員或查閱你的雲提供商或發行版文件,以確定你的叢集是否啟用了任何自願中斷源。如果未啟用任何源,你可以跳過建立 Pod 中斷預算。

處理中斷

以下是一些緩解非自願中斷的方法:

  • 確保你的 Pod 請求 它所需的資源。
  • 如果需要更高的可用性,請複製你的應用程式。(瞭解如何運行復制的無狀態有狀態應用程式。)
  • 對於運行復制應用程式時更高的可用性,請將應用程式分散到不同的機架(使用 反親和性)或不同可用區(如果使用 多可用區叢集)。

自願中斷的頻率各不相同。在一個基本的 Kubernetes 叢集中,沒有自動的自願中斷(只有使用者觸發的中斷)。但是,你的叢集管理員或託管提供商可能會執行一些導致自願中斷的額外服務。例如,推出節點軟體更新可能會導致自願中斷。此外,某些叢集(節點)自動擴縮的實現可能會導致自願中斷以進行碎片整理和節點壓縮。你的叢集管理員或託管提供商應該已經記錄了可能出現的自願中斷級別(如果有)。某些配置選項,例如在你的 Pod 規約中 使用優先順序類 也會導致自願(和非自願)中斷。

Pod 中斷預算

特性狀態: Kubernetes v1.21 [stable]

Kubernetes 提供了多項功能,可幫助你在引入頻繁自願中斷的情況下仍能執行高可用應用程式。

作為應用程式所有者,你可以為每個應用程式建立一個 PodDisruptionBudget (PDB)。PDB 限制了因自願中斷而同時停機的複製應用程式 Pod 的數量。例如,基於法定人數的應用程式希望確保執行的副本數量永遠不會低於法定人數所需的數量。一個 Web 前端可能希望確保提供負載的副本數量永遠不會低於總數的某個百分比。

叢集管理器和託管提供商應使用遵守 PodDisruptionBudgets 的工具,透過呼叫 驅逐 API,而不是直接刪除 Pod 或 Deployment。

例如,kubectl drain 子命令允許你將節點標記為停用。當你執行 kubectl drain 時,該工具會嘗試驅逐你正在停用的節點上的所有 Pod。kubectl 代表你提交的驅逐請求可能會暫時被拒絕,因此該工具會定期重試所有失敗的請求,直到目標節點上的所有 Pod 都終止,或者直到達到可配置的超時。

PDB 指定了應用程式可以容忍的副本數量,相對於它應該擁有的副本數量。例如,一個 .spec.replicas: 5 的 Deployment 在任何給定時間都應該有 5 個 Pod。如果它的 PDB 允許同時有 4 個 Pod,那麼驅逐 API 將允許一次自願中斷一個(但不能是兩個)Pod。

構成應用程式的 Pod 組使用標籤選擇器指定,該選擇器與應用程式控制器(Deployment、StatefulSet 等)使用的選擇器相同。

“預期”的 Pod 數量是根據管理這些 Pod 的工作負載資源的 .spec.replicas 計算的。控制平面透過檢查 Pod 的 .metadata.ownerReferences 來發現所有者工作負載資源。

非自願中斷 不能透過 PDB 阻止;但是它們確實會計入預算。

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

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

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

PodDisruptionBudget 示例

考慮一個有 3 個節點的叢集,從 node-1node-3。叢集正在執行多個應用程式。其中一個應用程式最初有 3 個副本,分別命名為 pod-apod-bpod-c。另一個不相關的、沒有 PDB 的 Pod,名為 pod-x,也顯示在其中。最初,Pod 的佈局如下:

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

所有 3 個 Pod 都是 Deployment 的一部分,它們共同擁有一個 PDB,該 PDB 要求在任何時候至少有 2 個 Pod 可用。

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

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

Deployment 注意到其中一個 Pod 正在終止,因此它建立了一個名為 pod-d 的替代 Pod。由於 node-1 已被隔離,它會落在另一個節點上。同時,某些程序也建立了 pod-y 作為 pod-x 的替代 Pod。

(注意:對於 StatefulSet,pod-a(可能被命名為 pod-0)需要完全終止,然後才能建立其替代 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,排空命令將阻塞,因為 Deployment 只有 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 時,它將被拒絕,因為這將導致 Deployment 只剩下一個可用 Pod。

Deployment 為 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 條件,以指示 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。
    • 無停機時間。
    • 最小的資源重複。
    • 允許更多的叢集管理自動化。
    • 編寫具有中斷容忍度的應用程式很棘手,但容忍自願中斷的工作與支援自動擴縮和容忍非自願中斷的工作在很大程度上是重疊的。

下一步

上次修改時間:2025 年 5 月 16 日太平洋標準時間下午 1:29:修復節點自動擴縮文件的錯誤連結 (307d6a6855)