解析Kubernetes 1.8中的基於Pod優先級的搶佔式調度

Author: xidianwangtao@gmail.comnode

Kubernetes 1.8中對scheduler的更新

  • 【Alpha】支持定義PriorityClass,並指定給Pod來定義Pod Priority;
  • 【Alpha】支持基於Pod Priority的搶佔式調度;
  • 【Alpha】Node Controller支持自動根據Node Condition給Node打上對應的Taints;

什麼是搶佔式調度?
在Kubernetes 1.8版本以前,當集羣資源不足時,用戶提交新的Pod建立請求後,該Pod會處於Pending狀態,直到集羣中有某個Node有足夠Available Resources時纔會調度成功。 從Kubernetes 1.8版本開始,這種狀況下scheduler會根據Pod's Priority進行調度,調度時會選擇最合適的Node並把該Node上lower Priority的Pods進行Premmption(Eviction)以釋放資源供該higher Priority Pod使用。這種調度時考慮Pod Priority的方式就是Kubernetes中的搶佔式調度,簡稱爲Preemption。nginx

在後續的版本中,Pod Priority還會用於節點的out-of-resource Eviction,關於kubelet eviction的工做機制和源碼分析,請參考個人對應博客:api

如何開啓或關閉該Feature

在Kubernetes 1.8中,Pod Priority和Preemption做爲Alpha特性,默認是disable的,若是你要使用該特性,須要給apiserver和scheduler添加以下參數並重啓:源碼分析

  • kube-apiserver xxx --feature-gates=PodPriority=true --runtime-config=scheduling.k8s.io/v1alpha1=true
  • kube-scheduler xxx --feature-gates=PodPriority=true

反過來,把上面的參數刪除並重啓,便可disable。spa

有個問題:若是我開啓了這個特性,而且建立了一些PriorityClass,而後還給某些Pod使用了,這個時候我再disable掉這個特性,會不會有問題?.net

答案是否認的!disable後,那些以前設置的Pod Priority field還會繼續存在,可是並沒什麼用處了,Preemption是關閉的。固然,你也不能給新的Pods引用PriorityClass了。code

建立PriorityClass

Enable後,接下來就是建立PriorityClass了:server

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

注意:PriorityClass是非namespace隔離的,是global的。所以metadata下面是不能設置namespace field的。blog

  • apiVersion: scheduling.k8s.io/v1alpha1 # enable的時候須要配置的runtime-config參數;
  • metadata.name: 設置PriorityClass的名字;
  • value: 32-bit 整型值,值越大表明優先級越高,可是必須小於等於 1 billion,大於 1 billion的值是給集羣內的critical system Pods保留的,表示該Priority的Pod是不能被搶佔的。
  • globalDefault: true or false,注意只能有一個PriorityClass的這個字段爲true,若是沒有一個PriorityClass的該字段爲true,則那些沒有明確引用PriorityClass的Pod的Priority value就爲最低值0.
  • description: String,寫給人看的備註,Kubernetes不作處理;

注意:ip

  • PriorityClass只會影響那些還沒建立的Pod,一旦Pod建立完成,那麼admission Controller就已經將Pod Spec中應用的PriorityClassName對應的PriorityClass的value設置到Pod的Priority field了。意味着你再修改PriorityClass的任何field,包括globalDefault,也不會影響已經建立完成的Pod。

  • 若是你刪除某個PriorityClass,那麼不會影響已經引用它的Pod Priority,但你不能用它來建立新的Pod了。這實際上是顯而易見的。

建立Pod並引用該PriorityClass

接下來,就是建立對應Priority的Pod了:

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

若是Pod.spec. priorityClassName中指定的PriorityClass不存在,則Pod會建立失敗;
前面也提到,建立Pod的時候Priority Admission Controller會根據PriorityClassName找到對應的PriorityClass,並將其value設置給Pod.spec.priority。

Preemption當前還存在的問題

  • 由於搶佔式調度evict低優先級Pod時,有一個優雅終止時間(默認30s),若是該Node上須要evict多個低優先級的Pod,那麼可能會須要很長的時間後,最終Pod才能調度到該Node上並啓動運行,那麼問題來了,這麼長時間的過去了,這個Node是否此時此刻仍是最適合這個Pod的呢?不必定!並且在大規模且建立Pod頻繁的集羣中,這種結果是常常的。意味着,當初合正確的調度決定,在真正落實的時候卻必定時正確的了。
  • 還不支持preempted pod時考慮PDB,計劃會在beta版中實現;
  • 目前premmpted pod時沒考慮Pending pod和victims pod的親和性:若是該pending pod要調度到的node上須要evict的lower Priority pods和該pending pod是親和的,目前直接evict lower Priority pods就可能會破壞這種pod親和性。
  • 不支持跨節點搶佔。好比pending Pod M要調度到Node A,而該Pending Pod M又與「同Node A一個zone的Node B上的Pod N」是基於zone topology反親和性的,目前的Alpha版本就會致使Pod M繼續Pending不能成功調度。若是後續支持跨界點搶佔,就能將lower Priority的Pod N從Node B上evict掉,從而保證了反親和性。

Taint Nodes by Condition

在Kubernetes 1.8以前,Node Condition是會直接干預調度的,邏輯是是這樣的,而且是沒法改變的:

  • kubelet會按期的將Node Condition傳給kube-apiserver並存於etcd。
  • kube-scheduler watch到Node Condition Pressure以後,會根據如下策略,阻止更多Pods Bind到該Node。
Node Condition Scheduler Behavior
MemoryPressure No new BestEffort pods are scheduled to the node.
DiskPressure No new pods are scheduled to the node.
- 當Node Condition包含Memory Pressure時,再也不容許BestEffort QoS Pods調度到該節點;
- 當Node Condition包含DiskPressure時,不容許任何pods調度到該節點。

從Kubernetes 1.6開始,kubelet和Node Controller支持自動根據Node Condition給Node打上相應的內置Taints,當時這些Taints只是會影響kubelet eviction,而不會影響調度。這有啥不一樣呢?區別就是,給Node打上Taints對調度來講是軟限制,能夠經過給pods加上對應的Tolerations就可能強制調度到那個節點。而在1.8以前,Node Condition影響調度是硬限制。

Node Condition和Taints的Map關係以下:

ConditionType Condition Status Effect Key
Ready True -
False NoExecute node.kubernetes.io/notReady
Unknown NoExecute node.kubernetes.io/unreachable
OutOfDisk True NoSchedule node.kubernetes.io/outOfDisk
False -
Unknown -
MemoryPressure True NoSchedule node.kubernetes.io/memoryPressure
False -
Unknown -
DiskPressure True NoSchedule node.kubernetes.io/diskPressure
False -
Unknown -
NetworkUnavailable True NoSchedule node.kubernetes.io/networkUnavailable
False -
Unknown -

總結

Kubernetes 1.8中基於Pod優先級進行搶佔式調度的特性都是Alpha,請謹慎在生產中使用,尤爲是要注意本文中「Preemption當前還存在的問題」小節中提到的不足。

  • 【Alpha】支持定義PriorityClass,並指定給Pod來定義Pod Priority;
  • 【Alpha】支持基於Pod Priority的搶佔式調度;
  • 【Alpha】Node Controller支持自動根據Node Condition給Node打上對應的Taints;

相信很快就能支持好搶佔式調度時支持Pod親和性、跨節點搶佔等特性了,那時就完美了。

相關文章
相關標籤/搜索