1. 程式人生 > >Kubernetes Pod 優先順序和搶佔

Kubernetes Pod 優先順序和搶佔

Kubernetes 1.8 及其以後的版本中可以指定 Pod 的優先順序。優先順序表明了一個 Pod 相對於其它 Pod 的重要性。當 Pod 無法被排程時,scheduler 會嘗試搶佔(驅逐)低優先順序的 Pod,使得這些掛起的 pod 可以被排程。在 Kubernetes 未來的釋出版本中,優先順序也會影響節點上資源回收的排序。

注: 搶佔不遵循 PodDisruptionBudget;更多詳細的資訊,請檢視 限制部分

怎麼樣使用優先順序和搶佔

想要在 Kubernetes 1.8 版本中使用優先順序和搶佔,請參考如下步驟:

  1. 啟用功能。
  2. 增加一個或者多個 PriorityClass。
  3. 建立擁有欄位 PriorityClassName 的 Pod,該欄位的值選取上面增加的 PriorityClass。當然,您沒有必要直接建立 pod,通常您可以把 PriorityClassName 增加到類似 Deployment 這樣的集合物件的 Pod 模板中。

以下章節提供了有關這些步驟的詳細資訊。

啟用優先順序和搶佔

Kubernetes 1.8 版本預設沒有開啟 Pod 優先順序和搶佔。為了啟用該功能,需要在 API server 和 scheduler 的啟動引數中設定:

--feature-gates=PodPriority=true

在 API server 中還需要設定如下啟動引數:

--runtime-config=scheduling.k8s.io/v1alpha1=true

功能啟用後,您能建立 PriorityClass,也能建立使用 PriorityClassName 集的 Pod。

如果在嘗試該功能後想要關閉它,那麼您可以把 PodPriority 這個命令列標識從啟動引數中移除,或者將它的值設定為false,然後再重啟 API server 和 scheduler。功能關閉後,原來的 Pod 會保留它們的優先順序欄位,但是優先順序欄位的內容會被忽略,搶佔不會生效,在新的 pod 建立時,您也不能設定 PriorityClassName。

PriorityClass

PriorityClass 是一個不受名稱空間約束的物件,它定義了優先順序類名跟優先順序整數值的對映。它的名稱通過 PriorityClass 物件 metadata 中的 name 欄位指定。值在必選的 value 欄位中指定。值越大,優先順序越高。

PriorityClass 物件的值可以是小於或者等於 10 億的 32 位任意整數值。更大的數值被保留給那些通常不應該取代或者驅逐的關鍵的系統級 Pod 使用。叢集管理員應該為它們想要的每個此類對映建立一個 PriorityClass 物件。

PriorityClass 還有兩個可選的欄位:globalDefault 和 description。globalDefault 表示 PriorityClass 的值應該給那些沒有設定 PriorityClassName 的 Pod 使用。整個系統只能存在一個 globalDefault 設定為 true 的 PriorityClass。如果沒有任何 globalDefault 為 true 的 PriorityClass 存在,那麼,那些沒有設定 PriorityClassName 的 Pod 的優先順序將為 0。

description 欄位的值可以是任意的字串。它向所有叢集使用者描述應該在什麼時候使用這個 PriorityClass。

注1:如果您升級已經存在的叢集環境,並且啟用了該功能,那麼,那些已經存在系統裡面的 Pod 的優先順序將會設定為 0。

注2:此外,將一個 PriorityClass 的 globalDefault 設定為 true,不會改變系統中已經存在的 Pod 的優先順序。也就是說,PriorityClass 的值只能用於在 PriorityClass 新增之後建立的那些 Pod 當中。

注3:如果您刪除一個 PriorityClass,那些使用了該 PriorityClass 的 Pod 將會保持不變,但是,該 PriorityClass 的名稱不能在新建立的 Pod 裡面使用。

PriorityClass 示例

description: "This priority class should be used for XYZ service pods only."

有了一個或者多個 PriorityClass 之後,您在建立 Pod 時就能在模板檔案中指定需要使用的 PriorityClass 的名稱。優先順序准入控制器通過 priorityClassName 欄位查詢優先順序數值並且填入 Pod 中。如果沒有找到相應的 PriorityClass,Pod 將會被拒絕建立。

下面的 YAML 是一個使用了前面建立的 PriorityClass 對 Pod 進行配置的示例。優先順序准入控制器會檢測配置檔案,並將該 Pod 的優先順序解析為 1000000。

  priorityClassName: high-priority

Pod 生成後,會進入一個佇列等待排程。scheduler 從佇列中選擇一個 Pod,然後嘗試將其排程到某個節點上。如果沒有任何節點能夠滿足 Pod 指定的所有要求,對於這個掛起的 Pod,搶佔邏輯就會被觸發。當前假設我們把掛起的 Pod 稱之為 P。搶佔邏輯會嘗試查詢一個節點,在該節點上移除一個或多個比 P 優先順序低的 Pod 後, P 能夠排程到這個節點上。如果節點找到了,部分優先順序低的 Pod 就會從該節點刪除。Pod 消失後,P 就能被排程到這個節點上了。

Pod 被搶佔時,受害者(被搶佔的 Pod)會有 優雅終止期。他們有大量的時間完成工作並退出。如果他們不這麼做,就會被強行殺死。這個優雅中止期在排程搶佔 Pod 以及掛起的 Pod(P)能夠被排程到節點(N)之間形成了一個時間間隔。在此期間,排程會繼續對其它掛起的 Pod 進行排程。當受害者退出或者終止的時候,scheduler 嘗試排程掛起佇列中的 Pod,在 scheduler 正式把 Pod P 排程到節點 N 之前,會繼續考慮把其它 Pod 排程到節點 N 上。這種情況下,當所有受害者退出時,很有可能 Pod P 已經不再適合於節點 N。因此,scheduler 將不得不搶佔節點 N 上的其它 Pod,或者搶佔其它節點,以便 P 能被排程。這種情況可能會在第二輪和隨後的搶佔回合中再次重複,而 P 可能在一段時間內得不到排程。這種場景可能會導致各種叢集中的問題,特別是在具有高 Pod 建立率的叢集中。

我們將在 Pod 搶佔的 beta 版本解決這個問題。計劃的解決方案可以在 這裡 找到。

Pod 破壞預算(Pod Disruption Budget,PDB) 允許應用程式所有者在自願中斷應用的同時限制應用副本的數量。然而,搶佔的 alpha 版本在選擇搶佔受害者時,並沒有遵循 PDB。我們計劃在 beta 版本增加對 PDB 遵循的支援,但即使是在 beta 版本,也只能做到盡力支援。scheduler 將會試圖查詢那些不會違反 PDB 的受害者,如果這樣的受害者沒有找到,搶佔依然會發生,即便違反了 PDB,這些低優先順序的 Pod 仍將被刪除。

在版本1.8中,只有當這個問題的答案是肯定的時候才考慮一個節點使用搶佔:“如果優先順序低於掛起的 Pod 的所有 Pod 從節點中移除後,掛起的 Pod 是否能夠被排程到該節點上?”

注: 搶佔沒有必要移除所有低優先順序的 Pod。如果在不移除所有低優先順序的 Pod 的情況下,掛起的 Pod 就能排程到節點上,那麼就只需要移除部分低優先順序的 Pod。即便如此,上述問題的答案還需要是肯定的。如果答案是否定的,搶佔功能不會考慮該節點。

如果掛起的 Pod 對節點上的一個或多個較低優先順序的 Pod 具有親和性,那麼在沒有那些較低優先順序的 Pod 的情況下,無法滿足 Pod 關聯規則。這種情況下,scheduler 不搶佔節點上的任何 Pod。它會去查詢另外的節點。scheduler 有可能會找到合適的節點,也有可能無法找到,因此掛起的 Pod 並不能保證都能被排程。

我們可能會在未來的版本中解決這個問題,但目前還沒有一個明確的計劃。我們也不會因為它而對 beta 或者 GA 版本的推進有所阻滯。部分原因是,要查詢滿足 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 之間有反親和性。
  • 在這個區域內沒有跟 Pod P 具備反親和性的其它 Pod。
  • 為了將 Pod P 排程到節點 N 上,Pod Q 需要被搶佔掉,但是 scheduler 不能執行跨節點的搶佔。因此,節點 N 將被視為不可排程節點。

如果將 Pod Q 從它的節點移除,反親和性隨之消失,那麼 Pod P 就有可能被排程到節點 N 上。

如果找到一個性能合理的演算法,我們可以考慮在將來的版本中增加跨節點搶佔。在這一點上,我們不能承諾任何東西,beta 或者 GA 版本也不會因為跨節點搶佔功能而有所阻滯。

參考:http://docs.kubernetes.org.cn/769.html