天天看點

kubernetes的排程機制k8s的排程機制

k8s的排程機制

scheduler元件

k8s排程器會将pod排程到資源滿足要求并且評分最高的node上。我們 可以使用多種規則比如:1.設定cpu、記憶體的使用要求;2.增加node的label,并通過pod.Spec.NodeSelector進行強比對;3.直接設定pod的nodeName,跳過排程直接下發。

k8s 1.2加入了一個實驗性的功能:affinity。意為親和性。這個特性的設計初衷是為了替代nodeSelector,并擴充更強大的排程政策。

排程器的工作機制是這樣的:

一、預備工作

1、緩存所有的node節點,記錄他們的規格:cpu、記憶體、磁盤空間、gpu顯示卡數等;

2、緩存所有運作中的pod,按照pod所在的node進行區分,統計每個node上的pod request了多少資源。request是pod的QoS配置,可以參考

之前的文章

3、list & watch pod資源,當檢查到有新的Pending狀态的pod出現,就将它加入到排程隊列中。

4、排程器的worker元件從隊列中取出pod進行排程。

二、排程過程

1、先将目前所有的node放入隊列;

2、執行predicates算法,對隊列中的node進行篩選。這裡算法檢查了一些pod運作的必要條件,包括port不沖突、cpu和記憶體資源QoS(如果有的話)必須滿足、挂載volume(如果有的話)類型必須比對、nodeSelector規則必須比對、硬性的affinity規則(下文會提到)必須比對、node的狀态(condition)必須正常,taint_toleration硬規則(下文會提到)等等。

2、執行priorities算法,對隊列中剩餘的node進行評分,這裡有許多評分項,各個項目有各自的權重:整體cpu,記憶體資源的平衡性、node上是否有存在要求的鏡像、同rs的pod是否有排程、node affinity的軟規則、taint_toleration軟規則(下文會提到)等等。

3、最終評分最高的node會被選出。即代碼中

suggestedHost, err := sched.schedule(pod)

一句(

plugin/pkg/scheduler/scheduler.go

)的傳回值。

4、排程器執行

assume

方法,該方法在pod排程到node之前,就以“該pod運作在目标node上” 為場景更新排程器緩存中的node 資訊,也即預備工作中的1、2兩點。這麼做是為了讓pod在真正排程到node上時,排程器也可以同時做後續其他pod的排程工作。

5、排程器執行

bind

方法,該方法建立一個Binding資源,apiserver檢查到建立該資源時,會主動更新pod的

nodeName

字段。完成排程。

nodeSelector

舉例:

apiVersion: v1 kind: Pod metadata: name: nginx labels: env: test spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent nodeSelector: disktype: ssd           

上面這個pod會且僅會被排程到帶有

disktype: ssd

這個label的node上。這是一種強規則,沒有妥協,必須遵守。

affinity 和 anti-affinity

  • 有親和性規則,那麼反親和性規則肯定也要有。
  • 親和性規則實作了更豐富的規則表達方式。并且包含了nodeSelector的硬規則和另一種軟規則。
  • 軟規則是一種優先規則,如果沒有符合這個優先規則的節點,它仍然會被進行排程。

node親和性

node親和性和nodeSelector類似,通過label進行可排程node的過濾,現在有兩種node親和性:

requiredDuringSchedulingIgnoredDuringExecution

preferredDuringSchedulingIgnoredDuringExecution

requiredDuringSchedulingIgnoredDuringExecution

強規則。和nodeSelector完全相同,以label進行強制的限制。需要指出的是:目前,如果一個node在運作時label發生了變化,變化後和其上運作的pod的

requiredDuringSchedulingIgnoredDuringExecution

不再比對,這個node上的pod也不會被驅逐,這個功能會在以後被改進,屆時會增加一種類型

RequiredDuringSchedulingRequiredDuringExecution

preferredDuringSchedulingIgnoredDuringExecution

軟規則。舉例來說:我們要将某個容器盡可能地排程到可用域X中,但如果不存在這個可用域或者可用域無法再運作pod,排程器也允許這個pod被排程到其他可用域。

以下是一個包含了強規則和軟規則的案例:

apiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/e2e-az-name operator: In values: - e2e-az1 - e2e-az2 preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: another-node-label-key operator: In values: - another-node-label-value containers: - name: with-node-affinity image: gcr.io/google_containers/pause:2.0           

該案例表明,這個pod隻允許被排程到帶有

kubernetes.io/e2e-az-name=e2e-az1或e2e-az2

的label的node上,也即隻允許被排程到e2e-az1或者e2e-az2兩個可用域中;另外,pod要盡量排程到包含

another-node-label-key

的值為

another-node-label-value

的node上。

matchExpressions

結構記錄各種表達式,一個表達式包含

key

,

operator

values

,分别表示關鍵字、關鍵字比對關系、關鍵字比對值。比對關系包括:

In

NotIn

Exists

DoesNotExist

Gt

Lt

NotIn

DoesNotExist

是node anti-affinity的一種表現。

如果一個pod的描述資訊中同時包含了

nodeSelector

nodeAffinity

,那麼排程時兩個規則都要滿足。

如果一個

nodeAffinity

中包含了多條

nodeSelectorTerms

, 排程器隻需要滿足其中一條; 如果一個

nodeSelectorTerms

中記錄了多條

matchExpressions

,那麼排程器要滿足所有的

matchExpressions

inter-pod affinity 和 anti-affinity

這兩個特性都包含在1.4版本中,上面的親和性是node親和性,這個就是pod親和性,簡而言之,要把pod排程到某個node上,這個node上已有的pod能滿足、或盡量滿足某些條件。這個特性用

pod.spec.affinity.podAffinity

pod.spec.affinity.podAntiAffinity

來表示。

pod親和性的規則可以這麼表示:

這個pod應該(或者不應該)運作在節點X上,X上必須已經運作了一個或多個滿足規則Y的pod。規則Y的表達方式類似于一個labelSelector并關聯了一個namespace清單:

namespaces

(若沒有則表示“allnamespaces”),X可能是node或一個az,我們通過字段

topologyKey

來規劃X,即所有的X都要滿足

topologyKey

相同,一般

topologyKey

是一個label的key。

為什麼要有namespace清單?因為和node不同,pod是有分namespace的,是以pod的label也是有分namespace的。在這種情況下,規則Y必須要指明自己這個規則要适用于哪些namespace。比如node上運作的是

hy

這個namespace下的pod,即便pod的label和規則Y的nodeSelector都相同,我們也視為不符合規則。

和node親和性一樣,pod親和性也包含兩個(硬規則和軟規則):

  • requiredDuringSchedulingIgnoredDuringExecution

    : 硬規則。
  • preferredDuringSchedulingIgnoredDuringExecution

舉個例子:

apiVersion: v1 kind: Pod metadata: name: with-pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: failure-domain.beta.kubernetes.io/zone podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: security operator: In values: - S2 topologyKey: kubernetes.io/hostname containers: - name: with-pod-affinity image: gcr.io/google_containers/pause:2.0           

上面的pod模闆使用了podAffinity的硬規則和podAntiAffinity的軟規則。

  • podAffinity規則中

    topologyKey

    是zone,也就是可用域,說明這條規則可以規劃處排程到的域,首先,node上必須至少有一個running狀态的pod包含key為

    security

    ,value為

    S1

    的label。隻要滿足這個條件,那麼這個node和其同一個域(擁有相同的

    failure-domain.beta.kubernetes.io/zone

    為key,且值相同的label)的node均會被排程。
  • podAntiAffinity規則中

    topologyKey

    是hostname,表明該規則約定了某種node盡量不會被排程到,這種node上已經運作了包含key為

    security

    S2

    的label的pod。
  • 假如現在有node a,b,c,其中a和b擁有相同的zone,且b上運作了一個pod,這個pod有一個label,key為

    security

    S1

    。那麼我們建立如上的一個親和性規則的3副本時,三個副本都會被排程到a或者b上。假如b上同時運作了一個pod,這個pod有一個label,key為

    security

    S2

    ,那麼所有的副本都會排程到node a上。

taint toleration

node 可以被打上污點标記,并配置污點容忍政策。而pod的描述資訊中如果包含了相同的污點容忍政策,就可以被排程到這個node上,反之則不可、或盡量不允許。

硬性規則

給node a 打上污點 name=huang, 政策為不可排程:

kubectl taint nodes a name=huang:NoSchedule

若我建立的pod中包含如下描述:

tolerations:
- key: "name"  operator: "Equal"  value: "huang"  effect: "NoSchedule"           

則這個pod可以容忍有這類污點的node,即可以排程到node a,當然,也可以用如下的描述:

tolerations:
- key: "name"  operator: "Exist"  effect: "NoSchedule"           

類似的硬性規則展現在

effect

字段中,還有

NoExecute

,它比

NoSchedule

更嚴格,不止pod不能排程上去,node上原有的pod如果不能容忍污點,就會被驅逐(eviction),配合字段

tolerationSeconds

可以規定這些會被驅逐的pod能在node上呆多久。

軟規則

除了

NoExecute

NoSchedule

,還有一條軟規則:

PreferNoSchedule

.配置

effect=PreferNoSchedule

後,沒有相關污點政策的pod會盡量避免排程到該node上。

本文轉自SegmentFault-

kubernetes的排程機制

繼續閱讀