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 也具有兩個選用欄位:globalDefaultdescriptionglobalDefault 欄位表示此 PriorityClass 的值應適用於沒有 priorityClassName 的 Pod。系統中只能存在一個將 globalDefault 設定為 true 的 PriorityClass。如果沒有將 globalDefault 設定為 true 的 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 之後,您可以建立 Pod,並在 Pod 的規格中指定其中一個 PriorityClass 名稱。優先順序許可控制器會使用 priorityClassName 欄位,並填入優先順序的整數值。如果找不到優先順序類別,則 Pod 會被拒絕。

以下 YAML 範例是一個 Pod 配置,其使用先前範例中建立的 PriorityClass。優先順序許可控制器會檢查規格,並將 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,並嘗試將其排程到節點上。如果找不到滿足 Pod 所有指定需求的節點,則會為待處理的 Pod 觸發搶佔邏輯。我們將待處理的 Pod 稱為 P。搶佔邏輯會嘗試尋找一個節點,在該節點上移除一個或多個優先順序低於 P 的 Pod,將使 P 能夠排程到該節點上。如果找到這樣的節點,則會從該節點驅逐一個或多個優先順序較低的 Pod。在這些 Pod 移除後,P 就可以排程到該節點上。

使用者可見的資訊

當 Pod P 搶佔節點 N 上的一個或多個 Pod 時,Pod P 狀態的 nominatedNodeName 欄位會設定為節點 N 的名稱。此欄位有助於排程器追蹤為 Pod P 保留的資源,並向使用者提供有關其叢集中搶佔的資訊。

請注意,Pod P 不一定會排程到「提名節點」。排程器總是先嘗試「提名節點」,然後才迭代任何其他節點。在受害者 Pod 被搶佔後,它們會獲得其正常終止期限。如果在排程器等待受害者 Pod 終止時,另一個節點變得可用,則排程器可能會使用另一個節點來排程 Pod P。因此,Pod 規格的 nominatedNodeNamenodeName 並不總是相同的。此外,如果排程器在節點 N 上搶佔 Pod,但隨後到達優先順序高於 Pod P 的 Pod,則排程器可能會將節點 N 給予新的較高優先順序的 Pod。在這種情況下,排程器會清除 Pod P 的 nominatedNodeName。透過這樣做,排程器使 Pod P 有資格搶佔另一個節點上的 Pod。

搶佔的限制

搶佔受害者的正常終止

當 Pod 被搶佔時,受害者會獲得其正常終止期限。它們有這麼多時間來完成其工作並退出。如果它們沒有退出,則會被強制終止。此正常終止期限在排程器搶佔 Pod 的時間點與待處理的 Pod (P) 可以排程到節點 (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 之間沒有其他反親和性案例。
  • 為了在節點 N 上排程 Pod P,可以搶佔 Pod Q,但排程器不會執行跨節點搶佔。因此,Pod P 將被視為在節點 N 上無法排程。

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

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

疑難排解

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

Pod 被不必要地搶佔

搶佔會從資源壓力下的叢集中移除現有的 Pod,以便為更高優先順序的待處理 Pod 騰出空間。如果您錯誤地為某些 Pod 指定了高優先順序,則這些非預期的高優先順序 Pod 可能會在您的叢集中造成搶佔。Pod 優先順序是透過在 Pod 的規格中設定 priorityClassName 欄位來指定的。然後,優先順序的整數值會被解析並填入 podSpecpriority 欄位。

為了解決此問題,您可以變更這些 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,並且如果搶佔它們會導致 PDB 受到侵犯,則排程器可能會選擇另一個具有更高優先順序 Pod 的節點。

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

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

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

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

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

有關更多詳細資訊,請參閱Pod 選擇以進行 kubelet 驅逐

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

下一步

上次修改時間:2024 年 2 月 19 日下午 1:54 PST:修正排程器章節中的尾隨空格 (2f298d2077)