Pod 優先順序和搶佔

功能狀態:`Kubernetes v1.14 [stable]`

Pod 可以有優先順序。優先順序表示 Pod 相對於其他 Pod 的重要性。如果 Pod 無法被排程,排程器會嘗試搶佔(驅逐)低優先順序的 Pod,以便使得待處理 Pod 可以被排程。

如何使用優先順序和搶佔

要使用優先順序和搶佔,請執行以下操作:

  1. 新增一個或多個 PriorityClass

  2. 建立 Pod,並將 `priorityClassName` 設定為其中一個新增的 PriorityClass。當然,你不需要直接建立 Pod;通常,你會將 `priorityClassName` 新增到 Deployment 等集合物件的 Pod 模板中。

繼續閱讀以獲取有關這些步驟的更多資訊。

PriorityClass

PriorityClass 是一個非名稱空間物件,它定義了從優先順序類名稱到優先順序整數值的對映。該名稱在 PriorityClass 物件的元資料中的 `name` 欄位中指定。該值在必需的 `value` 欄位中指定。值越高,優先順序越高。PriorityClass 物件的名稱必須是有效的DNS 子域名,並且不能以 `system-` 為字首。

一個 PriorityClass 物件可以具有小於或等於 10 億的任何 32 位整數值。這意味著 PriorityClass 物件的值範圍為 -2147483648 到 1000000000(包括)。較大的數字保留給表示關鍵系統 Pod 的內建 PriorityClass。叢集管理員應為每個他們想要的此類對映建立一個 PriorityClass 物件。

PriorityClass 還有兩個可選欄位:`globalDefault` 和 `description`。`globalDefault` 欄位表示該 PriorityClass 的值應該用於沒有 `priorityClassName` 的 Pod。系統中只能存在一個 `globalDefault` 設定為 true 的 PriorityClass。如果沒有設定 `globalDefault` 的 PriorityClass,則沒有 `priorityClassName` 的 Pod 的優先順序為零。

`description` 欄位是一個任意字串。它旨在告知叢集使用者何時應該使用此 PriorityClass。

關於 PodPriority 和現有叢集的注意事項

  • 如果你升級一個沒有此功能的現有叢集,你現有 Pod 的優先順序實際上為零。

  • 新增一個 `globalDefault` 設定為 `true` 的 PriorityClass 不會改變現有 Pod 的優先順序。此類 PriorityClass 的值僅用於在新增 PriorityClass 之後建立的 Pod。

  • 如果你刪除一個 PriorityClass,使用已刪除 PriorityClass 名稱的現有 Pod 保持不變,但你無法建立更多使用已刪除 PriorityClass 名稱的 Pod。

PriorityClass 示例

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for XYZ service pods only."

非搶佔式 PriorityClass

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

具有 `preemptionPolicy: Never` 的 Pod 將被置於排程佇列中,排在低優先順序 Pod 之前,但它們不能搶佔其他 Pod。一個等待排程的非搶佔式 Pod 將留在排程佇列中,直到有足夠的資源可用並可以被排程。非搶佔式 Pod 與其他 Pod 一樣,受排程器回退機制的影響。這意味著,如果排程器嘗試排程這些 Pod 但它們無法被排程,它們將被以較低的頻率重試,允許其他低優先順序 Pod 在它們之前被排程。

非搶佔式 Pod 仍然可能被其他高優先順序 Pod 搶佔。

`preemptionPolicy` 預設為 `PreemptLowerPriority`,這將允許該 PriorityClass 的 Pod 搶佔低優先順序 Pod(這是現有的預設行為)。如果 `preemptionPolicy` 設定為 `Never`,則該 PriorityClass 中的 Pod 將是非搶佔式的。

一個示例用例是資料科學工作負載。使用者可能提交一個他們希望優先於其他工作負載的任務,但又不希望透過搶佔正在執行的 Pod 來丟棄現有工作。具有 `preemptionPolicy: Never` 的高優先順序任務將在叢集資源“自然”可用時,優先於其他排隊中的 Pod 被排程。

非搶佔式 PriorityClass 示例

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority-nonpreempting
value: 1000000
preemptionPolicy: Never
globalDefault: false
description: "This priority class will not cause other pods to be preempted."

Pod 優先順序

擁有一個或多個 PriorityClass 後,你可以建立在規範中指定其中一個 PriorityClass 名稱的 Pod。優先順序准入控制器使用 `priorityClassName` 欄位並填充優先順序的整數值。如果找不到優先順序類,則 Pod 被拒絕。

以下 YAML 是一個使用前面示例中建立的 PriorityClass 的 Pod 配置示例。優先順序准入控制器檢查規範並將 Pod 的優先順序解析為 1000000。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  priorityClassName: high-priority

Pod 優先順序對排程順序的影響

當啟用 Pod 優先順序時,排程器會根據它們的優先順序對待處理的 Pod 進行排序,並且一個待處理的 Pod 會被放在排程佇列中優先順序較低的其他待處理 Pod 之前。因此,如果高優先順序 Pod 的排程要求得到滿足,它可能會比低優先順序 Pod 更早被排程。如果此類 Pod 無法被排程,排程器將繼續並嘗試排程其他低優先順序 Pod。

搶佔

當 Pod 被建立時,它們會進入一個佇列等待排程。排程器從佇列中選擇一個 Pod 並嘗試將其排程到 Node 上。如果沒有找到滿足 Pod 所有指定要求的 Node,則會為待處理的 Pod 觸發搶佔邏輯。我們稱待處理的 Pod 為 P。搶佔邏輯會嘗試找到一個 Node,如果從該 Node 中移除一個或多個優先順序低於 P 的 Pod,則 P 就可以被排程到該 Node 上。如果找到這樣的 Node,一個或多個低優先順序 Pod 將從該 Node 中被驅逐。在 Pod 被移除後,P 就可以被排程到該 Node 上。

使用者公開的資訊

當 Pod P 搶佔 Node N 上的一個或多個 Pod 時,Pod P 狀態的 `nominatedNodeName` 欄位被設定為 Node N 的名稱。該欄位有助於排程器跟蹤為 Pod P 保留的資源,並向用戶提供叢集中搶佔的資訊。

請注意,Pod P 不一定會排程到“提名節點”。排程器總是嘗試“提名節點”,然後才迭代任何其他節點。被搶佔的受害者 Pod 在被搶佔後會獲得它們的優雅終止期。如果排程器在等待受害者 Pod 終止期間有另一個節點變得可用,排程器可能會使用另一個節點來排程 Pod P。因此,Pod 規範的 `nominatedNodeName` 和 `nodeName` 不總是相同的。此外,如果排程器搶佔了節點 N 上的 Pod,但隨後一個優先順序高於 Pod P 的 Pod 到來,排程器可能會將節點 N 分配給新的高優先順序 Pod。在這種情況下,排程器會清除 Pod P 的 `nominatedNodeName`。透過這樣做,排程器使得 Pod P 可以在另一個節點上搶佔 Pod。

搶佔的侷限性

搶佔受害者的優雅終止

當 Pod 被搶佔時,受害者會獲得它們的優雅終止期。它們有足夠的時間來完成工作並退出。如果它們不退出,它們將被殺死。這個優雅終止期在排程器搶佔 Pod 和待處理 Pod (P) 可以排程到 Node (N) 之間造成了一個時間間隔。在此期間,排程器會繼續排程其他待處理的 Pod。隨著受害者退出或被終止,排程器會嘗試排程等待佇列中的 Pod。因此,排程器搶佔受害者和 Pod P 被排程之間通常會有一個時間間隔。為了最大限度地減少這個間隔,可以將低優先順序 Pod 的優雅終止期設定為零或一個較小的數字。

支援 PodDisruptionBudget,但不保證

PodDisruptionBudget (PDB) 允許應用程式所有者限制複製應用程式在自願中斷時同時宕機的 Pod 數量。Kubernetes 在搶佔 Pod 時支援 PDB,但尊重 PDB 是盡力而為的。排程器會嘗試找到在搶佔時不會違反其 PDB 的受害者,但如果找不到此類受害者,搶佔仍會發生,低優先順序 Pod 將被移除,即使它們的 PDB 被違反。

低優先順序 Pod 上的 Pod 間親和性

僅當這個問題的答案為是時,才考慮對一個節點進行搶佔:“如果所有優先順序低於待處理 Pod 的 Pod 都從節點中移除,待處理 Pod 還能排程到該節點上嗎?”

如果一個待處理的 Pod 與節點上一個或多個低優先順序 Pod 存在 Pod 間親和性,那麼在沒有這些低優先順序 Pod 的情況下,Pod 間親和性規則將無法滿足。在這種情況下,排程器不會搶佔該節點上的任何 Pod。相反,它會尋找另一個節點。排程器可能會找到合適的節點,也可能找不到。不保證待處理的 Pod 能夠被排程。

我們建議的解決方案是隻建立與同等或更高優先順序 Pod 的 Pod 間親和性。

跨節點搶佔

假設正在考慮對節點 N 進行搶佔,以便將待處理的 Pod P 排程到 N 上。只有當另一個節點上的 Pod 被搶佔時,P 才可能在 N 上變得可行。以下是一個示例:

  • Pod P 正在考慮用於節點 N。
  • Pod Q 在與節點 N 相同的區域中的另一個節點上執行。
  • Pod P 與 Pod Q 具有區域範圍的反親和性 (`topologyKey: topology.kubernetes.io/zone`)。
  • Pod P 與該區域中的其他 Pod 之間沒有其他反親和性情況。
  • 為了將 Pod P 排程到節點 N,Pod Q 可以被搶佔,但排程器不會執行跨節點搶佔。因此,Pod P 將被視為無法排程到節點 N 上。

如果 Pod Q 從其節點中移除,則 Pod 反親和性衝突將消失,Pod P 可能可以排程到節點 N 上。

如果需求足夠大,並且我們能找到一個性能合理的演算法,我們可能會在未來的版本中考慮新增跨節點搶佔。

故障排除

Pod 優先順序和搶佔可能會產生意外的副作用。以下是一些潛在問題及其處理方法的示例。

Pod 被不必要地搶佔

搶佔是在資源緊張的叢集中移除現有 Pod,以便為更高優先順序的待處理 Pod 騰出空間。如果你錯誤地給某些 Pod 設定了高優先順序,這些無意中獲得高優先順序的 Pod 可能會導致你的叢集中發生搶佔。Pod 優先順序透過設定 Pod 規範中的 `priorityClassName` 欄位來指定。然後,優先順序的整數值會被解析並填充到 `podSpec` 的 `priority` 欄位中。

要解決此問題,你可以更改這些 Pod 的 `priorityClassName` 以使用較低的優先順序類,或將該欄位留空。預設情況下,空的 `priorityClassName` 解析為零。

當 Pod 被搶佔時,被搶佔的 Pod 將記錄事件。搶佔只應在叢集資源不足以容納某個 Pod 時發生。在這種情況下,只有當待處理 Pod(搶佔者)的優先順序高於受害者 Pod 時才會發生搶佔。當沒有待處理 Pod,或者待處理 Pod 的優先順序等於或低於受害者時,搶佔不應發生。如果在此類情況下發生搶佔,請提交問題。

Pod 被搶佔,但搶佔者未被排程

當 Pod 被搶佔時,它們會獲得其請求的優雅終止期,預設情況下為 30 秒。如果受害者 Pod 未在此期限內終止,它們將被強制終止。一旦所有受害者消失,搶佔者 Pod 就可以被排程。

當搶佔者 Pod 等待受害者消失時,可能會建立另一個更高優先順序的 Pod,並且它正好適合同一個節點。在這種情況下,排程器將排程更高優先順序的 Pod,而不是搶佔者。

這是預期行為:更高優先順序的 Pod 應該取代較低優先順序的 Pod。

高優先順序 Pod 在低優先順序 Pod 之前被搶佔

排程器會嘗試查詢可以執行待處理 Pod 的節點。如果未找到節點,排程器會嘗試從任意節點中移除優先順序較低的 Pod,以便為待處理的 Pod 騰出空間。如果具有低優先順序 Pod 的節點無法執行待處理的 Pod,排程器可能會選擇另一個具有更高優先順序 Pod 的節點(相對於其他節點上的 Pod)進行搶佔。受害者 Pod 的優先順序仍然必須低於搶佔者 Pod。

當有多個節點可用於搶佔時,排程器會嘗試選擇優先順序最低的 Pod 集合所在的節點。但是,如果這些 Pod 具有在搶佔後會違反的 PodDisruptionBudget,那麼排程器可能會選擇另一個具有更高優先順序 Pod 的節點。

當存在多個可用於搶佔的節點且上述任何情況都不適用時,排程器會選擇優先順序最低的節點。

Pod 優先順序與服務質量之間的互動

Pod 優先順序和 QoS 類別 是兩個正交的功能,它們之間很少有互動,並且沒有預設的限制根據 Pod 的 QoS 類別設定其優先順序。排程器的搶佔邏輯在選擇搶佔目標時不會考慮 QoS。搶佔會考慮 Pod 優先順序,並嘗試選擇一組優先順序最低的目標。只有在移除最低優先順序 Pod 不足以讓排程器排程搶佔者 Pod,或者最低優先順序 Pod 受到 `PodDisruptionBudget` 保護時,才會考慮搶佔更高優先順序的 Pod。

kubelet 使用優先順序來確定節點壓力驅逐的 Pod 順序。你可以使用 QoS 類別來估計 Pod 最有可能被驅逐的順序。kubelet 根據以下因素對 Pod 進行驅逐排序:

  1. 資源匱乏使用量是否超過請求量
  2. Pod 優先順序
  3. 相對於請求量的資源使用量

有關詳細資訊,請參閱kubelet 驅逐的 Pod 選擇

當 Pod 的使用量未超過其請求量時,kubelet 節點壓力驅逐不會驅逐 Pod。如果優先順序較低的 Pod 未超過其請求量,它將不會被驅逐。而優先順序較高但超過其請求量的另一個 Pod 可能會被驅逐。

下一步

上次修改時間:2025 年 1 月 20 日太平洋標準時間上午 8:58:刪除過期的評審者 (58b4f374b8)