1. 程式人生 > 其它 >[原始碼分析-kubernetes]1.排程器設計

[原始碼分析-kubernetes]1.排程器設計

排程器設計

概述

我們先整體瞭解一下Scheduler的設計原理,然後再看這些過程是如何用程式碼實現的。關於排程器的設計在官網有介紹,我下面結合官網給的說明,簡化掉不影響理解的複雜部分,和大家介紹一下Scheduler的工作過程。

官方描述如下:

The Kubernetes scheduler runs as a process alongside the other master components such as the API server. Its interface to the API server is to watch for Pods with an empty PodSpec.NodeName, and for each Pod, it posts a binding indicating where the Pod should be scheduled.

簡單翻譯一下,也就是說Scheduler是一個跑在其他元件邊上的獨立程式,對接Apiserver尋找PodSpec.NodeName為空的Pod,然後用post的方式傳送一個api呼叫,指定這些pod應該跑在哪個node上。

通俗地說,就是scheduler是相對獨立的一個元件,主動訪問api server,尋找等待排程的pod,然後通過一系列排程演算法尋找哪個node適合跑這個pod,然後將這個pod和node的繫結關係發給api server,從而完成了排程的過程。

原始碼層級

從高level看,scheduler的原始碼可以分為3層:

  • cmd/kube-scheduler/scheduler.go
    : main() 函式入口位置,在scheduler過程開始被呼叫前的一系列初始化工作。
  • pkg/scheduler/scheduler.go: 排程框架的整體邏輯,在具體的排程演算法之上的框架性的程式碼。
  • pkg/scheduler/core/generic_scheduler.go: 具體的計算哪些node適合跑哪些pod的演算法。

排程演算法

排程過程整體如下圖所示:

對於一個給定的pod
+---------------------------------------------+
|             可用於排程的nodes如下:           |
|  +--------+     +--------+     +--------+   |
|  | node 1 |     | node 2 |     | node 3 |   |
|  +--------+     +--------+     +--------+   |
+----------------------+----------------------+
                       |
                       v
+----------------------+----------------------+
初步過濾: node 3 資源不足
+----------------------+----------------------+
                       |
                       v
+----------------------+----------------------+
|                 剩下的nodes:                 |
|     +--------+               +--------+     |
|     | node 1 |               | node 2 |     |
|     +--------+               +--------+     |
+----------------------+----------------------+
                       |
                       v
+----------------------+----------------------+
優先順序演算法計算結果:    node 1: 分數=2
                     node 2: 分數=5
+----------------------+----------------------+
                       |
                       v
            選擇分值最高的節點 = node 2

Scheduler為每個pod尋找一個適合其執行的node,大體分成三步:

  1. 通過一系列的“predicates”過濾掉不能執行pod的node,比如一個pod需要500M的記憶體,有些節點剩餘記憶體只有100M了,就會被剔除;
  2. 通過一系列的“priority functions”給剩下的node排一個等級,分出三六九等,尋找能夠執行pod的若干node中最合適的一個node;
  3. 得分最高的一個node,也就是被“priority functions”選中的node勝出了,獲得了跑對應pod的資格。

Predicates 和 priorities 策略

Predicates是一些用於過濾不合適node的策略 . Priorities是一些用於區分node排名(分數)的策略(作用在通過predicates過濾的node上). K8s預設內建了一些predicates 和 priorities 策略,官方文件介紹地址: scheduler_algorithm.md. Predicates 和 priorities 的程式碼分別在:

  • pkg/scheduler/algorithm/predicates/predicates.go
  • pkg/scheduler/algorithm/priorities.

Scheduler 的拓展性

我們可以選擇哪些預置策略生效,也可以新增自己的策略。幾個月前我司有個奇葩排程需求,當時我就是通過增加一個priorities策略,然後重新編譯了一個Scheduler來實現的需求。

排程策略的修改

預設排程策略是通過defaultPredicates()defaultPriorities()函式定義的,原始碼在 pkg/scheduler/algorithmprovider/defaults/defaults.go,我們可以通過命令列flag --policy-config-file來覆蓋預設行為。所以我們可以通過配置檔案的方式或者修改pkg/scheduler/algorithm/predicates/predicates.go /pkg/scheduler/algorithm/priorities,然後註冊到defaultPredicates()/defaultPriorities()來實現。配置檔案類似下面這個樣子:

{
"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}
	],
"hardPodAffinitySymmetricWeight" : 10,
"alwaysCheckAllPredicates" : false
}

ok,看到這裡大夥應該在流程上對Scheduler的原理有個感性的認識了,下一節我們就開始看一下Scheduler原始碼是怎麼寫的。

引用連結:

gitbook:https://farmer-hutao.github.io/k8s-source-code-analysis/
github:https://hub.fastgit.org/daniel-hutao/k8s-source-code-analysis