Kubernetes Scheduler調度詳解


1.Kubernetes Scheduler簡介

Kubernetes 調度器(Scheduler)是Kubernetes的核心組件;用戶或者控制器創建Pod之后,調度器通過 kubernetes 的 watch 機制來發現集群中新創建且尚未被調度到 Node 上的 Pod。調度器會將發現的每一個未調度的 Pod 調度到一個合適的 Node 上來運行。調度器會依據下文的調度原則來做出調度選擇。

kube-scheduler 給一個 pod 做調度選擇包含兩個步驟:過濾、打分

過濾階段:會將所有滿足 Pod 調度需求的 Node 選出來。例如,PodFitsResources 過濾函數會檢查候選 Node 的可用資源能否滿足 Pod 的資源請求。在過濾之后,得出一個 Node 列表,里面包含了所有可調度節點;通常情況下,這個 Node 列表包含不止一個 Node。如果這個列表是空的,代表這個 Pod 不可調度。

 
打分階段:調度器會為 Pod 從所有可調度節點中選取一個最合適的 Node,根據當前啟用的打分規則,調度器會給每一個可調度節點進行打分。最后,kube-scheduler 會將 Pod 調度到得分最高的 Node 上。如果存在多個得分最高的 Node,kube-scheduler 會從中隨機選取一個。

 

我們可以使用多種規則比如:

  • 設置cpu、內存的使用要求;
  • 增加node的label,並通過pod.Spec.NodeSelector進行強匹配;
  • 直接設置pod的nodeName,跳過調度直接下發。

注:k8s 1.2加入了一個實驗性的功能:affinity。意為親和性。這個特性的設計初衷是為了替代nodeSelector,並擴展更強大的調度策略。

 

 

2.Scheduler工作原理

  • 節點預選(Predicate):排除完全不滿足條件的節點,如內存大小,端口等條件不滿足。
  • 節點優先級排序(Priority):根據優先級選出最佳節點
  • 節點擇優(Select):根據優先級選定節點

  1. 首先用戶通過 Kubernetes 客戶端 Kubectl 提交創建 Pod 的 Yaml 的文件,向Kubernetes 系統發起資源請求,該資源請求被提交到

  2. Kubernetes 系統中,用戶通過命令行工具 Kubectl 向 Kubernetes 集群即 APIServer 用 的方式發送“POST”請求,即創建 Pod 的請求。

  3. APIServer 接收到請求后把創建 Pod 的信息存儲到 Etcd 中,從集群運行那一刻起,資源調度系統 Scheduler 就會定時去監控 APIServer

  4. 通過 APIServer 得到創建 Pod 的信息,Scheduler 采用 watch 機制,一旦 Etcd 存儲 Pod 信息成功便會立即通知APIServer,

  5. APIServer會立即把Pod創建的消息通知Scheduler,Scheduler發現 Pod 的屬性中 Dest Node 為空時(Dest Node=””)便會立即觸發調度流程進行調度。

  6. 而這一個創建Pod對象,在調度的過程當中有3個階段:節點預選、節點優選、節點選定,從而篩選出最佳的節點

    • 節點預選:基於一系列的預選規則對每個節點進行檢查,將那些不符合條件的節點過濾,從而完成節點的預選

    • 節點優選:對預選出的節點進行優先級排序,以便選出最合適運行Pod對象的節點

    • 節點選定:從優先級排序結果中挑選出優先級最高的節點運行Pod,當這類節點多於1個時,則進行隨機選擇

 

3.Pod調度

Kubernetes中,Pod通常是容器的載體,一般需要通過Deployment、DaemonSet、RC、Job等對象來完成一組Pod的調度與自動控制功能。

3.1 Depolyment/RC自動調度

Deployment或RC的主要功能之一就是自動部署一個容器應用的多份副本,以及持續監控副本的數量,在集群內始終維持用戶指定的副本數量。

示例
[root@uk8s-m-01 study]# vi nginx-deployment.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment-01
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

[root@uk8s-m-01 study]# kubectl get deployments
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment-01   3/3     3            3           30s
[root@uk8s-m-01 study]# kubectl get rs
NAME                             DESIRED   CURRENT   READY   AGE
nginx-deployment-01-5754944d6c   3         3         3       75s
[root@uk8s-m-01 study]# kubectl get pod | grep nginx
nginx-deployment-01-5754944d6c-hmcpg   1/1     Running     0          84s
nginx-deployment-01-5754944d6c-mcj8q   1/1     Running     0          84s
nginx-deployment-01-5754944d6c-p42mh   1/1     Running     0          84s

 

3.2 NodeSelector定向調度

當需要手動指定將Pod調度到特定Node上,可以通過Node的標簽(Label)和Pod的nodeSelector屬性相匹配。

# kubectl label nodes <node-name> <label-key>=<label-value>

node節點創建對應的label后,可通過在定義Pod的時候加上nodeSelector的設置實現指定的調度。

示例
[root@uk8s-m-01 study]# kubectl label nodes 172.24.9.14 speed=io
node/172.24.9.14 labeled
[root@uk8s-m-01 study]# vi nginx-master-controller.yaml
kind: ReplicationController
metadata:
  name: nginx-master
  labels:
    name: nginx-master
spec:
  replicas: 1
  selector:
    name: nginx-master
  template:
    metadata:
      labels:
        name: nginx-master
    spec:
      containers:
      - name: master
        image: nginx:1.7.9
        ports:
        - containerPort: 80
      nodeSelector:
        speed: io

[root@uk8s-m-01 study]# kubectl create -f nginx-master-controller.yaml
[root@uk8s-m-01 study]# kubectl get pods -o wide
NAME                READY   STATUS    RESTARTS    AGE    IP            NODE
nginx-master-7fjgj  1/1     Running   0           82s    172.24.9.71   172.24.9.14
提示:可以將集群中具有不同特點的Node貼上不同的標簽,實現在部署時就可以根據應用的需求設置NodeSelector來進行指定Node范圍的調度。
注意:若在定義Pod中指定了NodeSelector條件,但集群中不存在符合該標簽的Node,即使集群有其他可供使用的Node,Pod也無法被成功調度。

 

3.3 NodeAffinity親和性調度

親和性調度機制極大的擴展了Pod的調度能力,主要增強功能如下:
  • 更具表達力,即更精細的力度控制;
  • 可以使用軟限制、優先采用等限制方式,即調度器在無法滿足優先需求的情況下,會使用其他次條件進行滿足;
  • 可以依據節點上正在運行的其他Pod的標簽來進行限制,而非節點本身的標簽,從而實現Pod之間的親和或互斥關系。
 
目前有兩種節點親和力表達:
  • requiredDuringSchedulingIgnoredDuringExecution:硬規則,必須滿足指定的規則,調度器才可以調度Pod至Node上(類似nodeSelector,語法不同)。
  • preferredDuringSchedulingIgnoredDuringExecution:軟規則,優先調度至滿足的Node的節點,但不強求,多個優先級規則還可以設置權重值。
  • IgnoredDuringExecution指:如果一個Pod所在的節點在Pod運行期間標簽發生了變化,不再符合該Pod的節點親和性需求,則系統將忽略Node上Label的變化,該Pod能繼續在該節點運行。

示例:條件1:只運行在amd64的節點上;盡量運行在ssd節點上。

[root@uk8s-m-01 study]# vi nodeaffinity-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/arch
            operator: In
            values:
            - amd64
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: disk-type
            operator: In
            values:
            - ssd
  containers:
  - name: with-node-affinity
    image: gcr.azk8s.cn/google_containers/pause:2.0

NodeAffinity操作語法;In、NotIn、Exists、DoesNotExist、Gt、Lt。NotIn和DoesNotExist可以實現互斥功能。

NodeAffinity規則設置注意事項:

  • 若同時定義nodeSelector和nodeAffinity,則必須兩個條件都滿足,Pod才能最終運行指定在Node上;;
  • 若nodeAffinity指定多個nodeSelectorTerms,則只需要其中一個能夠匹配成功即可;
  • 若nodeSelectorTerms中有多個matchExpressions,則一個節點必須滿足所有matchExpressions才能運行該Pod。

 

3.4 PodAffinity親和性調度

PodAffinity根據節點上正在運行的Pod標簽而不是Node標簽來判斷和調度,要求對節點和Pod兩個條件進行匹配。

規則描述為:若在具有標簽X的Node上運行了一個或多個符合條件Y的Pod,則Pod應該(或者不應該)運行在這個Node上。

X通常為Node節點的機架、區域等概念,Pod是屬於某個命名空間,所以條件Y表達的是一個或全部命名空間中的一個Label Selector。

Pod親和性定義與PodSpec的affinity字段下的podAffinity字段里,互斥性定義於同一層次的podAntiAffinity子字段中。

舉例:
[root@uk8s-m-01 study]# vi nginx-flag.yaml    #創建名為pod-flag,帶有兩個標簽的Pod
apiVersion: v1
kind: Pod
metadata:
  name: pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: kubernetes.io/hostname
  containers:
  - name: with-pod-affinity
    image: gcr.azk8s.cn/google_containers/pause:2.0
[root@uk8s-m-01 study]# vi nginx-affinity-in.yaml    #創建定義標簽security=S1,對應如上Pod “Pod-flag”。
apiVersion: v1
kind: Pod
metadata:
  name: pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: kubernetes.io/hostname
  containers:
  - name: with-pod-affinity
    image: gcr.azk8s.cn/google_containers/pause:2.0

[root@uk8s-m-01 study]# kubectl create -f nginx-affinity-in.yaml
[root@uk8s-m-01 study]# kubectl get pods -o wide

提示:由上Pod親和力可知,兩個Pod處於同一個Node上。

 
[root@uk8s-m-01 study]# vi nginx-affinity-out.yaml    #創建不能與參照目標Pod運行在同一個Node上的調度策略
apiVersion: v1
kind: Pod
metadata:
  name: anti-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: failure-domain.beta.kubernetes.io/zone
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - nginx
        topologyKey: kubernetes.io/hostname
  containers:
  - name: anti-affinity
    image: gcr.azk8s.cn/google_containers/pause:2.0

[root@uk8s-m-01 study]# kubectl get pods -o wide    #驗證

 

3.5 Taints和Tolerations(污點和容忍)

Taint:使Node拒絕特定Pod運行;

Toleration:為Pod的屬性,表示Pod能容忍(運行)標注了Taint的Node。

Taint語法:$ kubectl taint nodes node1 key=value:NoSchedule

解釋:為node1加上一個Taint,該Taint的鍵為key,值為value,Taint的效果為NoSchedule。即除非特定聲明可以容忍此Taint,否則不會調度至node1上。

Toleration示例:
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"

 

tolerations:
- key: "key1"
  operator: "Exists"
  effect: "NoSchedule"

 

注意:Pod的Toleration聲明中的key和effect需要與Taint的設置保持一致,並且滿足以下條件:
  • operator的值是Exists(無須指定value);
  • operator的值是Equal並且value相等;
  • 空的key配合Exists操作符能夠匹配所有的鍵和值;
  • 空的effect匹配所有的effect。
 

若不指定operator,則默認值為Equal。

taint說明:系統允許在同一個Node上設置多個taint,也可以在Pod上設置多個toleration。Kubernetes調度器處理多個taint和toleration的邏輯順序:首先列出節點中所有的taint,然后忽略pod的toleration能夠匹配的部分,剩下的沒有忽略掉的taint就是對pod的效果。以下是幾種特殊情況:

  • 若剩余的taint中存在effect=NoSchedule,則調度器不會把該Pod調度到這一節點上;
  • 若剩余的taint中沒有NoSchedule效果,但有PreferNoSchedule效果,則調度器會嘗試不把這個Pod指派到此節點;
  • 若剩余taint的效果有NoSchedule,並且這個Pod已經在該節點上運行,則會被驅逐,若沒有在該節點上運行,也不會再被調度到該節點上。
示例:
$ kubectl taint node node1 key=value1:NoSchedule
$ kubectl taint node node1 key=value1:NoExecute
$ kubectl taint node node1 key=value2:NoSchedule
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value"
  effect: "NoSchedule"
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"

釋義:此Pod聲明了兩個容忍,且能匹配Node1的taint,但是由於沒有能匹配第三個taint的toleration,因此此Pod依舊不能調度至此Node。若該Pod已經在node1上運行了,那么在運行時設置了第3個taint,它還能繼續在node1上運行,這是因為Pod可以容忍前兩個taint。

通常,若node加上effect=NoExecute的taint,那么該Node上正在運行的所有無對應toleration的Pod都會被立刻驅逐,而具有相應toleration的Pod則永遠不會被驅逐。同時,系統可以給具有NoExecute效果的toleration加入一個可選的tolerationSeconds字段,表明Pod可以在taint添加到Node之后還能在此Node運行多久。 

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value"
  effect: "NoSchedule"
  tolerationSeconds: 3600

 釋義:若Pod正在運行,所在節點被加入一個匹配的taint,則這個pod會持續在該節點運行3600s后被驅逐。若在此期限內,taint被移除,則不會觸發驅逐事件。

Taints和Tolerations常用場景:
  • 獨占節點:

給特定的節點運行特定應用。

$ kubectl taint nodes 【nodename】 dedicated=groupName:NoSchedule

同時在Pod中設置對應的toleration配合,帶有合適toleration的Pod允許同時使用其他節點一樣使用有taint的節點。

  • 具有特殊硬件設備的節點

集群中部分特殊硬件(如安裝了GPU),則可以把不需要占用GPU的Pod禁止在此Node上調度。

  1 $ kubectl taint nodes 【nodename】 special=true:NoSchedule
  2 $ kubectl taint nodes 【nodename】 special=true:PreferNoSchedule
  • 定義Pod驅逐行為

NoExecute的taint對節點上正在運行的Pod有以下影響:

    • 沒有設置toleration的pod會被立刻驅逐;
    • 配置了對應toleration的pod,若沒有為tolerationSeconds賦值,則會一直保留在此節點中;
    • 配置了對應toleration的pod,且為tolerationSeconds賦值,則在指定時間后驅逐。

 

3.6 nodeName

nodeName:指定節點名稱,用於將Pod調度到指定的Node上,不經過調度器
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeName: kube-01

 注:上面的 pod 將指定運行在 kube-01 節點上。

使用 nodeName 來選擇節點的一些限制:

  • 如果指定的節點不存在,
  • 如果指定的節點沒有資源來容納 Pod,Pod 將會調度失敗並且其原因將顯示為, 比如 OutOfmemory 或 OutOfcpu。
  • 雲環境中的節點名稱並非總是可預測或穩定的
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM