天天看點

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

第18講:Kubernetes 排程和資源管理

這節課主要講三部分的内容:

  1. Kubernetes 的排程過程;
  2. Kubernetes 的基礎排程能力(資源排程、關系排程);
  3. Kubernetes 進階排程能力(優先級、搶占)。

另外,關于排程器架構和具體算法部分,會由我的同僚在下一節課為大家介紹。

一、Kubernetes 排程過程

首先來看第一部分 - Kubernetes 的排程過程。如下圖所示,畫了一個很簡單的 Kubernetes 叢集架構,它包括了一個 kube-ApiServer,一組 webhooks 的 Controller,以及一個預設的排程器 kube-Scheduler,還有兩台實體機節點 Node1 和 Node2,分别在上面部署了兩個 kubelet。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

我們來看一下,假如要向這個 Kubernetes 叢集送出一個 pod,它的排程過程是什麼樣的一個流程?

假設我們已經寫好了一個 yaml 檔案,就是下圖中的橙色圓圈 pod1,然後我們往 kube-ApiServer 裡面送出這個 yaml 檔案。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

此時 ApiServer 會先把這個待建立的請求路由給我們的 webhooks 的 Controlles 進行校驗。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

在通過校驗之後,ApiServer 會在叢集裡面生成一個 pod,但此時生成的 pod,它的 nodeName 是空的,并且它的 phase 是 Pending 狀态。在生成了這個 pod 之後,kube-Scheduler 以及 kubelet 都能 watch 到這個 pod 的生成事件,kube-Scheduler 發現這個 pod 的 nodeName 是空的之後,會認為這個 pod 是處于未排程狀态

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

接下來,它會把這個 pod 拿到自己裡面進行排程,通過一系列的排程算法,包括一系列的過濾和打分的算法後,Schedule 會選出一台最合适的節點,并且把這一台節點的名稱綁定在這個 pod 的 spec 上,完成一次排程的過程。

此時我們發現,pod 的 spec 上,nodeName 已經更新成了 Node1 這個 node,更新完 nodeName 之後,在 Node1 上的這台 kubelet 會 watch 到這個 pod 是屬于自己節點上的一個 pod。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力
kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

然後它會把這個 pod 拿到節點上進行操作,包括建立一些容器 storage 以及 network,最後等所有的資源都準備完成,kubelet 會把狀态更新為 Running,這樣一個完整的排程過程就結束了。

通過剛剛一個排程過程的示範,我們用一句話來概括一下排程過程:它其實就是在做一件事情,就是把 pod 放到合适的 node 上。

這裡有個關鍵字“合适”,什麼是合适呢?這裡給出了幾點合适定義的特點:

1、首先要滿足 pod 的資源要求;

2、其次要滿足 pod 的一些特殊關系的要求;

3、再次要滿足 node 的一些限制條件的要求;

4、最後還要做到整個叢集資源的合理利用。

做到這些要求之後,可以認為我們把 pod 放到了一個合适的節點上了。

接下來我會為大家介紹 Kubernetes 是怎麼做到滿足這些 pod 和 node 的要求的。

二、Kubernetes 基礎排程力

下面為大家介紹一下 Kubernetes 的基礎排程能力,Kubernetes 的基礎排程能力會用兩部分來展開介紹:

  1. 第一部分是資源排程——介紹一下 Kubernetes 基本的一些 Resources 的配置方式,還有 Qos 的概念,以及 Resource Quota 的概念和使用方式;
  2. 第二部分是關系排程——在關系排程上,介紹兩種關系場景:
    1. pod 和 pod 之間的關系場景,包括怎麼去親和一個 pod,怎麼去互斥一個 pod?
    2. pod 和 node 之間的關系場景,包括怎麼去親和一個 node,以及有一些 node 怎麼去限制 pod 排程上來。
kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

如何滿足 Pod 資源要求

pod 的資源配置方法

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

上圖是 pod spec 的一個 demo,我們的資源其實是填在 pod spec 裡面,Container 裡面有一個 resources 裡面的 key 裡面。

resources 其實包含兩個部分:第一部分是 request;第二部分是 limits。

這兩部分裡面的内容是一模一樣的,但是它代表的含義有所不同:request 代表的是對這個 pod 基本保底的一些資源要求;limit 代表的是對這個 pod 可用能力上限的一種限制。具體的 request、limit 的理念,其實都是一個 resources 的一個 map 結構,它裡面可以填不同的資源的 key。

我們可以大概分成四大類的基礎資源:

  • 第一類是 CPU 資源;
  • 第二類是 memory;
  • 第三類是 ephemeral-storage,一種臨時存儲;
  • 第四類是通用的擴充資源,比如說像 GPU。

在 CPU 上的話,比如說上面的例子,申請的是兩個 CPU,也可以寫成 2000m 這種十進制的轉換方式,來表達有些時候可能對 CPU 可能是一個小數的需求,比如說像 0.2 個,就是說 200m。在 memory 和 storage 之上,它是一個二進制的表達方式。如上圖右側所示,申請的是 1GB 的 memory,也可以轉化成一個 1024mi 的表達方式,這樣可以更清楚地表達我們對 memory 的需求。

在擴充資源上,Kubernetes 有一個要求,即擴充資源必須是整數的,是以我們沒法申請到 0.5 的 GPU 這樣的資源,隻能申請 1 個 GPU 或者 2 個 GPU,這裡為大家介紹一下基礎資源的申請方式。

接下來,我會詳細的給大家介紹一下 request 和 limit 到底有什麼差別,以及如何通過 request/limit 來引出 Qos 的概念。

Pod QoS 類型

K8s 在 pod resources 裡面提供了兩種填寫方式:第一種是 request,第二種是 limit。它其實是為使用者提供了對 Pod 一種彈性能力的定義。比如說我們可以對 request 填 2 個 CPU,對 limit 填 4 個 CPU,這樣其實代表了我希望是有 2 個 CPU 的保底能力,但其實是在閑置的時候,可以使用 4 個 GPU。

說到這個彈性能力,我們不得不提到一個概念:Qos 的概念。什麼是 Qos呢?Qos 全稱是 Quality of Service,它其實是 Kubernetes 用來表達一個 pod 在資源能力上的服務品質的标準,Kubernetes 提供了三類的 Qos Class:

  1. 第一類是 Guaranteed,它是一類高的 Qos Class,一般用 Guaranteed 來為一些需要資源保障能力的 pod 進行配置;
  2. 第二類是 Burstable,它其實是中等的一個 Qos label,一般會為一些希望有彈性能力的 pod 來配置 Burstable;
  3. 第三類是 BestEffort,通過名字我們也知道,它是一種盡力而為式的服務品質。

K8s 其實有一個不太好的地方,就是使用者沒法指定自己的 pod 是屬于哪一類 Qos,而是通過 request 和 limit 的組合來自動地映射上 Qos Class。

通過上圖的例子,大家可以看到:假如我送出的是上面的一個 spec,在 spec 送出成功之後,Kubernetes 會自動給補上一個 status,裡面是 qosClass: Guaranteed,使用者自己送出的時候,是沒法定義自己的 Qos 等級。是以将這種方式稱之為隐性的 Qos class 用法。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

Pod QoS 配置

接下來介紹一下,我們怎麼通過 request 和 limit 的組合來确定我們想要的 Qos level。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

Guaranteed Pod

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

首先我們如何建立出來一個 Guaranteed Pod?Kubernetes 裡面有一個要求:如果你要建立出一個 Guaranteed Pod,那麼你的基礎資源(就是包括 CPU 和 memory),必須它的 request==limit,其他的資源可以不相等。隻有在這種條件下,它建立出來的 pod 才是一種 Guaranteed Pod,否則它會屬于 Burstable,或者是 BestEffort Pod。

Burstable Pod

然後看一下,我們怎麼建立出來一個 Burstable Pod,Burstable Pod 的範圍比較寬泛,它隻要滿足 CPU/Memory  的 request 和 limit 不相等,它就是一種 Burstable Pod。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

比如說上面的例子,可以不用填寫 memory 的資源,隻要填寫 CPU 的資源,它就是一種 Burstable Pod。

BestEffort Pod

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

第三類 BestEffort Pod,它其實也是條件比較死的一種使用方式。它必須是所有資源的 request/limit 都不填,才是一種 BestEffort Pod。

是以這裡可以看到,通過 request 和 limit 不同的用法,可以組合出不同的 Pod Qos。

不同的 QoS 表現

接下來,為大家介紹一下:不同的 Qos 在排程和底層表現有什麼樣的不同?不同的 Qos,它其實在排程和底層表現上都有一些不一樣。比如說排程表現,排程器隻會使用 request 進行排程,也就是不管你配了多大的 limit,它都不會進行排程使用,它隻會使用 request 進行排程。

在底層上,不同的 Qos 表現更不相同。比如說 CPU,它其實是按 request 來劃分權重的,不同的 Qos,它的 request 是完全不一樣的,比如說像 Burstable 和 BestEffort,它可能 request 可以填很小的數字或者不填,這樣的話,它的權重其實是非常低的。像 BestEffort,它的權重可能是隻有 2,而 Burstable 或 Guaranteed,它的權重可以多到幾千。

另外,當我們開啟了 kubelet 的一個特性,叫 cpu-manager-policy=static 的時候,我們 Guaranteed Qos,如果它的 request 是一個整數的話,比如說配了 2,它會對 Guaranteed Pod 進行綁核。也就是具體像下面這個例子,它配置設定 CPU0 和 CPU1 給 Guaranteed Pod。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

非整數的 Guaranteed/Burstable/BestEffort,它們的 CPU 會放在一塊,組成一個 CPU share pool,比如說像上面這個例子,這台節點假如說有 8 個核,已經配置設定了 2 個核給整數的 Guaranteed 綁核,那麼剩下的 6 個核 CPU2~CPU7,它會被非整數的 Guaranteed/Burstable/BestEffort 共享,然後它們會根據不同的權重劃分時間片來使用 6 個核的 CPU。

另外在 memory 上也會按照不同的 Qos 進行劃分:OOMScore。比如說 Guaranteed,它會配置預設的 -998 的 OOMScore;Burstable 的話,它會根據記憶體設計的大小和節點的關系來配置設定 2-999 的 OOMScore。BestEffort 會固定配置設定 1000 的 OOMScore,OOMScore 得分越高的話,在實體機出現 OOM 的時候會優先被 kill 掉。

另外在節點上的 eviction 動作上,不同的 Qos 也是不一樣的,比如說發生 eviction 的時候,會優先考慮驅逐 BestEffort 的 pod。是以不同的 Qos 其實在底層的表現是截然不同的。這也反過來要求我們在生産過程中,根據不同業務的要求和屬性來配置資源的 Limits 和 Request,做到合理的規劃 Qos Class。

資源 Quota

在生産中我們還會遇到一個場景:假如叢集是由多個人同時送出的,或者是多個業務同時在使用,我們肯定要限制某個業務或某個人送出的總量,防止整個叢集的資源都會被使用掉,導緻另一個業務沒有資源使用。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

Kubernetes 給我們提供了一個能力叫:ResourceQuota 方法。它可以做到限制 namespace 資源用量。

具體的做法如上圖右側的 yaml 所示,可以看到它的 spec 包括了一個 hard 和 scopeSelector。hard 内容其實和 Resourcelist 很像,這裡可以填一些基礎的資源。但是它比 ResourceList 更豐富一點,它還可以填寫一些 Pod,這樣可以限制 Pod 數量能力。然後 scopeSelector 為這個 Resource 方法定義更豐富的索引能力。

比如上面的例子中,索引出非 BestEffort 的 pod,限制的 cpu 是 1000 個,memory 是 200G,Pod 是 10 個,然後 Scope 除了提供 NotBestEffort,它還提供了更豐富的索引範圍,包括 Terminating/Not Terminating,BestEffort/NotBestEffort,PriorityClass。

當我們建立了這樣的 ResourceQuota 作用于叢集,如果使用者真的用超了資源,表現的行為是:它在送出 Pod spec 時,會收到一個 forbidden 的 403 錯誤,提示 exceeded quota。這樣使用者就無法再送出 cpu 或者是 memory,或者是 Pod 數量的資源。

假如再送出一個沒有包含在這個 ResourceQuota 方案裡面的資源,還是能成功的。這就是 Kubernetes 裡 ResourceQuota 的基本用法。 我們可以用 ResourceQuota 方法來做到限制每一個 namespace 的資源用量,進而保證其他使用者的資源使用。

小結:如何滿足 Pod 資源要求?

上面介紹完了基礎資源的使用方式,也就是我們做到了如何滿足 Pod 資源要求。下面做一個小結:

  • Pod 要配置合理的資源要求
    • CPU/Memory/EphemeralStorage/GPU
  • 通過 Request 和 Limit 來為不同業務特點的 Pod 選擇不同的 QoS
    • Guaranteed:敏感型,需要業務保障
    • Burstable:次敏感型,需要彈性業務
    • BestEffort:可容忍性業務
  • 為每個 NS 配置 ResourceQuota 來防止過量使用,保障其他人的資源可用

如何滿足 Pod 與 Pod 關系要求?

接下來給大家介紹一下 Pod 的關系排程,首先是 Pod 和 Pod 的關系排程。我們在平時使用中可能會遇到一些場景:比如說一個 Pod 必須要和另外一個 Pod 放在一起,或者不能和另外一個 Pod 放在一起。

在這種要求下, Kubernetes 提供了兩類能力:

  • 第一類能力稱之為 Pod 親和排程:PodAffinity;
  • 第二類就是 Pod 反親和排程:PodAntAffinity。

Pod 親和排程

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

首先我們來看 Pod 親和排程,假如我想把一個 Pod 和另一個 Pod 放在一起,這時我們可以看上圖中的執行個體寫法,填寫上 podAffinity,然後填上 required 要求。

在這個例子中,必須要排程到帶了 k1: v1 的 Pod 所在的節點,并且打散粒度是按照節點粒度去打散索引的。這種情況下,假如能找到帶 k1= v1 的 Pod 所在節點,就會排程成功。假如這個叢集不存在這樣的 Pod 節點,或者是資源不夠的時候,那就會排程失敗。這是一個嚴格的親和排程,我們叫做嘗試親和排程。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

有些時候我們并不需要這麼嚴格的排程政策。這時候可以把 required 改成 preferred,變成一個優先親和排程。也就是優先可以排程帶 k2= v2 的 Pod 所在節點。并且這個 preferred 裡面可以是一個 list 選擇,可以填上多個條件,比如權重等于 100 的是 k2= v2,權重等于 10 的是 k1=v1。那排程器在排程的時候會優先把這個 Pod 配置設定到權重分更高的排程條件節點上去。

Pod 反親和排程

上面介紹了親和排程,而反親和排程其實是與親和排程比較像的。比如說功能上是取反的,在文法上基本上是一樣的,隻是 podAffinity 換成了 podAntiAffinity,做到的效果也是 required 強制反親和,以及一個 preferred 優先反親和。

我這裡同時舉了兩個例子:一個是禁止排程到帶了 key: k1 标簽的 Pod 所在節點;另一個是優先反親和排程到帶了 key: k2 标簽的 Pod 所在節點。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力
kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

另外 Kubernetes 除了 In 這個 Operator 文法之外,還提供了更多豐富的文法組合來給大家使用。比如說 In/NotIn/Exists/DoesNotExist 這些組合方式。上圖的例子用的是 In,比如說第一個強制反親和例子裡面,相當于我們必須要禁止排程到帶了 key: k1 标簽的 Pod 所在節點。

同樣的功能也可以使用 Exists,Exists 範圍可能會比 In 範圍更大,當 Operator 填了 Exists,就不需要再填寫 values。它做到的效果就是禁止排程到帶了 key: k1 标簽的 Pod 所在節點,不管 values 是什麼值,隻要帶了 k1 這個 key 标簽的 Pod 所在節點,都不能排程過去。

以上就是 Pod 與 Pod 之間的關系排程。

如何滿足 Pod 與 Node 關系排程

Pod 與 Node 的關系排程又稱之為 Node 親和排程,主要給大家介紹兩類使用方法。

NodeSelector

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

第一類是 NodeSelector,這是一類相對比較簡單的玩法。比如說有個場景:必須要排程 Pod 到帶了 k1: v1 标簽的 Node 上,這時可以在 Pod 的 spec 中填寫一個 nodeSelector 要求。nodeSelector 其實是一個 map 結構,裡面可以直接寫上對 node 标簽的要求,比如 k1: v1。這樣我的 Pod 就會強制排程到帶了 k1: v1 标簽的 Node 上。

NodeAffinity

NodeSelector 是一個非常簡單的玩法,但這個玩法有個問題:它是一個正常性排程,假如我想優先排程,就沒法用 nodeSelector 來做。于是 Kubernetes 社群又新加了一個玩法,叫做 NodeAffinity。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

它和 PodAffinity 有點類似,也提供了兩類排程的政策:

  • 第一類是 required,必須排程到某一類 Node 上;
  • 第二類是 preferred,就是優先排程到某一類 Node 上。

它的基本文法和上文中的 PodAffinity 以及 PodAntiAffinity 也是類似的。在 Operator 上,NodeAffinity 提供了比 PodAffinity 更豐富的 Operator 内容。增加了 Gt 和 Lt,數值比較的玩法。當使用 Gt 的時候,values 隻能填寫數字。

Node 标記/容忍

還有第三類排程,可以通過給 Node 打一些标記,來限制 Pod 排程到某些 Node 上。Kubernetes 把這些标記稱之為 Taints,它的字面意思是污染。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

那我們如何限制 Pod 排程到某些 Node 上呢?比如說現在有個 node 叫 demo-node,這個節點有問題,我想限制一些 Pod 排程上來。這時可以給這個節點打一個 taints,taints 内容包括 key、value、effect:

  • key 就是配置的鍵值
  • value 就是内容
  • effect 是标記了這個 taints 行為是什麼

目前 Kubernetes 裡面有三個 taints 行為:

  1. NoSchedule 禁止新的 Pod 排程上來;
  2. PreferNoSchedul 盡量不排程到這台;
  3. NoExecute 會 evict 沒有對應 toleration 的 Pods,并且也不會排程新的上來。這個政策是非常嚴格的,大家在使用的時候要小心一點。

如上圖綠色部分,給這個 demo-node 打了 k1=v1,并且 effect 等于 NoSchedule 之後。它的效果是:建立的 Pod  沒有專門容忍這個 taint,那就沒法排程到這個節點上去了。

假如有些 Pod 是可以排程到這個節點上的,應該怎麼來做呢?這時可以在 Pod 上打一個 Pod Tolerations。從上圖中藍色部分可以看到:在 Pod 的 spec 中填寫一個 Tolerations,它裡面也包含了 key、value、effect,這三個值和 taint 的值是完全對應的,taint 裡面的 key,value,effect 是什麼内容,Tolerations 裡面也要填寫相同的内容。

Tolerations 還多了一個選項 Operator,Operator 有兩個 value:Exists/Equal。Equal 的概念是必須要填寫 value,而 Exists 就跟上文說的 NodeAffinity 一樣,不需要填寫 value,隻要 key 值對上了,就認為它跟 taints 是比對的。

上圖中的例子,給 Pod 打了一個 Tolerations,隻有打了這個 Tolerations 的 Pod,才能排程到綠色部分打了 taints 的 Node 上去。這樣的好處是 Node 可以有選擇性的排程一些 Pod 上來,而不是所有的 Pod 都可以排程上來,這樣就做到了限制某些 Pod 排程到某些 Node 的效果。

小結

我們已經介紹完了 Pod/Node 的特殊關系和條件排程,來做一下小結。

首先假如有需求是處理 Pod 與 Pod 的時候,比如 Pod 和另一個 Pod 有親和的關系或者是互斥的關系,可以給它們配置下面的參數:

  • PodAffinity
  • PodAntiAffinity

假如存在 Pod 和 Node 有親和關系,可以配置下面的參數:

  • NodeSelector
  • NodeAffinity

假如有些 Node 是限制某些 Pod 排程的,比如說一些故障的 Node,或者說是一些特殊業務的 Node,可以配置下面的參數:

  • Node -- Taints
  • Pod -- Tolerations

三、Kubernetes 進階排程能力

介紹完了基礎排程能力之後,下面來了解一下進階排程能力。

優先級排程

優先級排程和搶占,主要概念有:

  • Priority
  • Preemption

首先來看一下排程過程提到的四個特點,我們如何做到叢集的合理利用?當叢集資源足夠的話,隻需要通過基礎排程能力就能組合出合理的使用方式。但是假如資源不夠,我們怎麼做到叢集的合理利用呢?通常的政策有兩類:

  • 先到先得政策 (FIFO) -簡單、相對公平,上手快
  • 優先級政策 (Priority) - 符合日常公司業務特點

在實際生産中,如果使用先到先得政策,是一種不公平的政策,因為公司業務裡面肯定是有高優先級的業務和低優先級的業務,是以優先級政策會比先到先得政策更能夠符合日常公司業務特點。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

接着介紹一下優先級政策下的優先級排程是什麼樣的一個概念。比如說有一個 Node 已經被一個 Pod 占用了,這個 Node 隻有 2 個 CPU。另一個高優先級 Pod 來的時候,低優先級的 Pod 應該把這兩個 CPU 讓給高優先級的 Pod 去使用。低優先級的 Pod 需要回到等待隊列,或者是業務重新送出。這樣的流程就是優先級搶占排程的一個流程。

在 Kubernetes 裡,PodPriority 和 Preemption,就是優先級和搶占的特點,在 v1.14 版本中變成了 stable。并且 PodPriority 和 Preemption 預設都是開啟的。

優先級排程配置

怎麼使用?

如何使用優先級排程呢?需要建立一個 priorityClass,然後再為每個 Pod 配置上不同的 priorityClassName,這樣就完成了優先級以及優先級排程的配置。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

首先來看一下如何建立一個 priorityClass。上圖右側定義了兩個 demo:

  • 一個是建立名為 high 的 priorityClass,它是高優先級,得分為 10000;
  • 然後還建立了一個 low 的 priorityClass,它的得分是 100。

并且在第三部分給 Pod 配置上了 high,Pod2 上配置了 low priorityClassName,藍色部分顯示了 pod 的 spec 的配置位置,就是在 spec 裡面填寫一個 priorityClassName: high。這樣 Pod 和 priorityClass 做完配置,就為叢集開啟了一個 priorityClass 排程。

内置優先級配置

當然 Kubernetes 裡面還内置了預設的優先級。如 DefaultpriorityWhenNoDefaultClassExistis,如果叢集中沒有配置 DefaultpriorityWhenNoDefaultClassExistis,那所有的 Pod 關于此項數值都會被設定成 0。

另一個内置優先級是使用者可配置最大優先級限制:HighestUserDefinablePriority = 10000000000(10 億)

系統級别優先級:SystemCriticalPriority = 20000000000(20 億)

内置系統級别優先級:

  • system-cluster-critical
  • system-node-critical

這就是優先級排程的基本配置以及内置的優先級配置。

優先級排程過程

當做完上面的配置後,整個優先級排程是怎樣一個流程呢?下面将會介紹一下簡單的過程。

首先介紹一下隻觸發優先級排程但是沒有觸發搶占排程的流程。

假如有一個 Pod1 和 Pod2,Pod1 配置了高優先級,Pod2 配置了低優先級。同時送出 Pod1 和 Pod2 到排程隊列裡。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力
kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力
kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力
kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力
kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

排程器處理隊列的時候會挑選一個高優先級的 Pod1 進行排程,經過排程過程把 Pod1 綁定到 Node1 上。其次再挑選一個低優先的 Pod2 進行同樣的過程,綁定到 Node1 上。這樣就完成了一個簡單的優先級排程的流程。

優先級搶占過程

假如高優先級的 Pod 在排程的時候沒有資源,那麼會是一個怎麼樣的流程呢?

首先是跟上文同樣的場景,但是提前在 Node1 上放置了 Pod0,占去了一部分資源。同樣有 Pod1 和 Pod2 待排程,Pod1 的優先級大于 Pod2。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

假如先把 Pod2 排程上去,它經過一系列的排程過程綁定到了 Node1 上。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

緊接着再排程 Pod1,因為 Node1 上已經存在了兩個 Pod,資源不足,是以會遇到排程失敗。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

在排程失敗時 Pod1 會進入搶占流程,這時會進行整個叢集的節點篩選,最後挑出要搶占的 Pod 是 Pod2,此時排程器會把 Pod2 從 Node1 上移除資料。再把 Pod1 排程到 Node1 上。這樣就完成了一次搶占排程的流程。

優先級搶占政策

接下來介紹一下具體的搶占政策和搶占的流程是什麼樣的。

kubernetes-雲原生技術進階 第18講:Kubernetes 排程和資源管理第18講:Kubernetes 排程和資源管理一、Kubernetes 排程過程二、Kubernetes 基礎排程力三、Kubernetes 進階排程能力

上圖右側是整個優先級搶占的排程流程,也就是 kube-scheduler 的工作流程。首先一個 Pod 進入搶占的時候,會判斷 Pod 是否擁有搶占的資格,有可能上次已經搶占過一次。如果符合搶占資格,它會先對所有的節點進行一次過濾,過濾出符合這次搶占要求的節點,如果不符合就過濾掉這批節點。

接着從過濾剩下的節點中,挑選出合适的節點進行搶占。這次搶占的過程會模拟一次排程,也就是把上面優先級低的 Pod 先移除出去,再把待搶占的 Pod 嘗試能否放置到此節點上。然後通過這個過程選出一批節點,進入下一個過程叫 ProcessPreemptionWithExtenders。這是一個擴充的鈎子,使用者可以在這裡加一些自己搶占節點的政策,如果沒有擴充的鈎子,這裡面是不做任何動作的。

接下來的流程叫做 PickOneNodeForPreemption,就是從上面 selectNodeForPreemption list 裡面挑選出最合适的一個節點,這是有一定的政策的。上圖左側簡單介紹了一下政策:

  • 優先選擇打破 PDB 最少的節點;
  • 其次選擇待搶占 Pods 中最大優先級最小的節點;
  • 再次選擇待搶占 Pods 優先級加和最小的節點;
  • 接下來選擇待搶占 Pods 數目最小的節點;
  • 最後選擇擁有最晚啟動 Pod 的節點;

通過這五步串行政策過濾之後,會選出一個最合适的節點。然後對這個節點上待搶占的 Pod 進行 delete,這樣就完成了一次待搶占的過程。

小結

簡單介紹了一下排程的進階政策,在叢集資源緊張的時候也能合理排程資源。我們回顧一下做了哪些事情:

  • 建立自定義的一些優先級類别 (PriorityClass);
  • 給不同類型 Pods 配置不同的優先級 (PriorityClassName);
  • 通過組合不同類型 Pods 運作和優先級搶占讓叢集資源和排程彈性起來。