天天看點

k8s基礎(13)之scheduler排程器k8s基礎(13)之scheduler排程器

k8s基礎(13)之scheduler排程器

kube-scheduler是kubernetes系統的核心元件質疑,主要負責整個叢集資源的排程功能,根據特定的排程算法和政策,将Pod排程到最優的一個工作節點上面去,進而更加的合理、更加充分的利用叢集的資源。

排程器流程

scheduler 是Kubernetes的排程器,它的主要作用就是根據特定的排程算法和排程政策将Pod排程到合适的Node節點上去,是一個獨立的二進制程式,當我們通過API 或者kubectl工具發送建立Pod的指令後,apiserver會将資料寫進ETCD中,同時scheduler監聽API Server,通過scheduler内部的比對規則(預選過程)将合适的Node節點計算出,并進行打分(優選過程)。最後傳回給apiserver,并由apiserver 通知kubelet進行建立并将相關資訊寫進ETCD

k8s基礎(13)之scheduler排程器k8s基礎(13)之scheduler排程器

排程主要分為以下幾個部分

  • 預選過程 過濾不滿足條件的節點,這個過程稱為

    Predicates

  • 優選過程 對通過的節點按照優先級排序,稱之為

    Priorities

  • 最後從中選擇優先級最高的節點

Predicates

階段首先會周遊全部節點,過濾不滿足條件的節點,屬于強制性規則,這一階段輸出的所有滿足要求的Node将被記錄并作為第二階段的輸入,如果所有的節點都不滿足條件,那麼Pod将會一直處于Pending狀态,直到有節點滿足條件,在這期間排程器會不斷的重試

Priorities

階段即再次對節點進行篩選,如果有多個節點都滿足條件的話,那麼系統會根據節點的優先級(priorites)大小對節點進行排序,最後選擇優先級最高的節點來部署Pod應用

k8s基礎(13)之scheduler排程器k8s基礎(13)之scheduler排程器

更詳細的流程是這樣的:

1.首先,用戶端通過 API Server 的 REST API 或者 kubectl 工具建立 Pod 資源 2.API Server 收到使用者請求後,存儲相關資料到 etcd 資料庫中 3.排程器監聽 API Server 檢視為排程(bind)的 Pod 清單,循環周遊地為每個 Pod 嘗試配置設定節點,這個配置設定過程就是我們上面提到的兩個階段:

  • 預選階段(Predicates),過濾節點,排程器用一組規則過濾掉不符合要求的 Node 節點,比如 Pod 設定了資源的 request,那麼可用資源比 Pod 需要的資源少的主機顯然就會被過濾掉
  • 優選階段(Priorities),為節點的優先級打分,将上一階段過濾出來的 Node 清單進行打分,排程器會考慮一些整體的優化政策,比如把 Deployment 控制的多個 Pod 副本分布到不同的主機上,使用最低負載的主機等等政策

4.經過上面的階段過濾後選擇打分最高的 Node 節點和 Pod 進行 binding 操作,然後将結果存儲到 etcd 中 5.最後被選擇出來的 Node 節點對應的 kubelet 去執行建立 Pod 的相關操作

其中Predicates過濾有一系列的算法可以使用,我們這裡簡單列舉幾個:

  • PodFitsResources:節點上剩餘的資源是否大于 Pod 請求的資源
  • PodFitsHost:如果 Pod 指定了 NodeName,檢查節點名稱是否和 NodeName 比對
  • PodFitsHostPorts:節點上已經使用的 port 是否和 Pod 申請的 port 沖突
  • PodSelectorMatches:過濾掉和 Pod 指定的 label 不比對的節點
  • NoDiskConflict:已經 mount 的 volume 和 Pod 指定的 volume 不沖突,除非它們都是隻讀的
  • CheckNodeDiskPressure:檢查節點磁盤空間是否符合要求
  • CheckNodeMemoryPressure:檢查節點記憶體是否夠用

除了這些過濾算法之外,還有一些其他的算法,更多更詳細的我們可以檢視源碼檔案:k8s.io/kubernetes/pkg/scheduler/algorithm/predicates/predicates.go。

而Priorities優先級是由一系列鍵值對組成的,鍵是該優先級的名稱,值是它的權重值,同樣,我們這裡給大家列舉幾個具有代表性的選項:

  • LeastRequestedPriority:通過計算 CPU 和記憶體的使用率來決定權重,使用率越低權重越高,當然正常肯定也是資源是使用率越低權重越高,能給别的 Pod 運作的可能性就越大
  • SelectorSpreadPriority:為了更好的高可用,對同屬于一個 Deployment 或者 RC 下面的多個 Pod 副本,盡量排程到多個不同的節點上,當一個 Pod 被排程的時候,會先去查找該 Pod 對應的 controller,然後檢視該 controller 下面的已存在的 Pod,運作 Pod 越少的節點權重越高
  • ImageLocalityPriority:就是如果在某個節點上已經有要使用的鏡像節點了,鏡像總大小值越大,權重就越高
  • NodeAffinityPriority:這個就是根據節點的親和性來計算一個權重值,後面我們會詳細講解親和性的使用方法

自定義排程

上面就是 kube-scheduler 預設排程的基本流程,除了使用預設的排程器之外,我們也可以自定義排程政策。

排程器擴充

kube-scheduler在啟動的時候可以通過

--policy-config-file

參數來指定排程政策檔案,我們可以根據我們自己的需要來組裝Predicates和Priority函數。選擇不同的過濾函數和優先級函數、控制優先級函數的權重、調整過濾函數的順序都會影響排程過程。

下面是官方的 Policy 檔案示例:

{
  "kind" : "Policy",
  "apiVersion" : "v1",
  "predicates" : [
      {"name" : "PodFitsHostPorts"},
      {"name" : "PodFitsResources"},
      {"name" : "NoDiskConflict"},
      {"name" : "NoVolumeZoneConflict"},
      {"name" : "MatchNodeSelector"},
      {"name" : "HostName"}
  ],
  "priorities" : [
      {"name" : "LeastRequestedPriority", "weight" : 1},
      {"name" : "BalancedResourceAllocation", "weight" : 1},
      {"name" : "ServiceSpreadingPriority", "weight" : 1},
      {"name" : "EqualPriority", "weight" : 1}
  ]
}
           

多排程器

如果預設的排程器不滿足要求,還可以部署自定義的排程器。并且,在整個叢集中還可以同時運作多個排程器執行個體,通過 podSpec.schedulerName 來選擇使用哪一個排程器(預設使用内置的排程器)

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  schedulerName: my-scheduler  # 選擇使用自定義排程器 my-scheduler
  containers:
  - name: nginx
    image: nginx:1.10
           

要開發我們自己的排程器也是比較容易的,比如我們這裡的 my-scheduler:

  • 首先需要通過指定的 API 擷取節點和 Pod
  • 然後選擇phase=Pending和schedulerName=my-scheduler的pod
  • 計算每個 Pod 需要放置的位置之後,排程程式将建立一個Binding對象
  • 然後根據我們自定義的排程器的算法計算出最适合的目标節點

優先級排程

與前面所講的排程優選政策中的優先級(Priorities)不同,前面所講的優先級指的是節點優先級,而我們這裡所說的優先級 pod priority 指的是 Pod 的優先級,高優先級的 Pod 會優先被排程,或者在資源不足低情況犧牲低優先級的 Pod,以便于重要的 Pod 能夠得到資源部署。

要定義 Pod 優先級,就需要先定義PriorityClass對象,該對象沒有 Namespace 的限制:

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

其中:

  • value為 32 位整數的優先級,該值越大,優先級越高
  • globalDefault用于未配置 PriorityClassName 的 Pod,整個叢集中應該隻有一個PriorityClass将其設定為 true

然後通過在 Pod 的spec.priorityClassName中指定已定義的PriorityClass名稱即可:

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

另外一個值得注意的是當節點沒有足夠的資源供排程器排程 Pod,導緻 Pod 處于 pending 時,搶占(preemption)邏輯就會被觸發。Preemption會嘗試從一個節點删除低優先級的 Pod,進而釋放資源使高優先級的 Pod 得到節點資源進行部署。

繼續閱讀