kubernetes系列教程(七)深入玩轉pod調度

關於作者 劉海平(HappyLau )雲計算高級顧問 目前在騰訊雲從事公有云相關工作,曾就職於酷狗,EasyStack,擁有多年公有云+私有云計算架構設計,運維,交付相關經驗,參與了酷狗,南方電網,國泰君安等大型私有云平臺建設,精通Linux,Kubernetes,OpenStack,Ceph等開源技術,在雲計算領域具有豐富實戰經驗,擁有RHCA/OpenStack/Linux授課經驗。

寫在前面

上一篇文章中kubernetes系列教程(六)kubernetes資源管理和服務質量初步介紹了kubernetes中的resource資源調度和服務質量Qos,介紹了kubernetes中如何定義pod的資源和資源調度,以及設置resource之後的優先級別Qos,接下來介紹kubernetes系列教程pod的調度機制。

1. Pod調度

1.1 pod調度概述

kubernets是容器編排引擎,其中最主要的一個功能是容器的調度,通過kube-scheduler實現容器的完全自動化調度,調度週期分爲:調度週期Scheduling Cycle和綁定週期Binding Cycle,其中調度週期細分爲過濾filter和weight稱重,按照指定的調度策略將滿足運行pod節點的node賽選出來,然後進行排序;綁定週期是經過kube-scheduler調度優選的pod後,由特定的node節點watch然後通過kubelet運行。

Pod調度機制

過濾階段包含預選Predicate和scoring排序,預選是篩選滿足條件的node,排序是最滿足條件的node打分並排序,預選的算法包含有:

  • CheckNodeConditionPred 節點是否ready
  • MemoryPressure 節點內存是否壓力大(內存是否足夠)
  • DiskPressure 節點磁盤壓力是否大(空間是否足夠)
  • PIDPressure 節點Pid是否有壓力(Pid進程是否足夠)
  • GeneralPred 匹配pod.spec.hostname字段
  • MatchNodeSelector 匹配pod.spec.nodeSelector標籤
  • PodFitsResources 判斷resource定義的資源是否滿足
  • PodToleratesNodeTaints 能容忍的污點pod.spec.tolerations
  • CheckNodeLabelPresence
  • CheckServiceAffinity
  • CheckVolumeBinding
  • NoVolumeZoneConflict

過濾條件需要檢查node上滿足的條件,可以通過kubectl describe node node-id方式查看,如下圖:

node調度條件condition

優選調度算法有:

  • least_requested 資源消耗最小的節點
  • balanced_resource_allocation 各項資源消耗最均勻的節點
  • node_prefer_avoid_pods 節點傾向
  • taint_toleration 污點檢測,檢測有污點條件的node,得分越低
  • selector_spreading 節點selector
  • interpod_affinity pod親和力遍歷
  • most_requested 資源消耗最大的節點
  • node_label node標籤

1. 2 指定nodeName調度

nodeName是PodSpec中的一個字段,可以通過pod.spec.nodeName指定將pod調度到某個具體的node節點上,該字段比較特殊一般都爲空,如果有設置nodeName字段,kube-scheduler會直接跳過調度,在特定節點上通過kubelet啓動pod。通過nodeName調度並非是集羣的智能調度,通過指定調度的方式可能會存在資源不均勻的情況,建議設置Guaranteed的Qos,防止資源不均時候Pod被驅逐evince。如下以創建一個pod運行在node-3上爲例:

  1. 編寫yaml將pod指定在node-3節點上運行
[root@node-1 demo]# cat nginx-nodeName.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-run-on-nodename
  annotations:
    kubernetes.io/description: "Running the Pod on specific nodeName"
spec:
  containers:
  - name: nginx-run-on-nodename
    image: nginx:latest
    ports:
    - name: http-80-port
      protocol: TCP
      containerPort: 80 
  nodeName: node-3       #通過nodeName指定將nginx-run-on-nodename運行在特定節點node-3上
  1. 運行yaml配置使之生效
[root@node-1 demo]# kubectl apply -f nginx-nodeName.yaml 
pod/nginx-run-on-nodename created
  1. 查看確認pod的運行情況,已運行在node-3節點
[root@node-1 demo]# kubectl get pods nginx-run-on-nodename -o wide 
NAME                    READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
nginx-run-on-nodename   1/1     Running   0          6m52s   10.244.2.15   node-3   <none>           <none>

1.2. 通過nodeSelector調度

nodeSelector是PodSpec中的一個字段,nodeSelector是最簡單實現將pod運行在特定node節點的實現方式,其通過指定key和value鍵值對的方式實現,需要node設置上匹配的Labels,節點調度的時候指定上特定的labels即可。如下以node-2添加一個app:web的labels,調度pod的時候通過nodeSelector選擇該labels:
  1. 給node-2添加labels
[root@node-1 demo]# kubectl label node node-2 app=web
node/node-2 labeled
  1. 查看校驗labels設置情況,node-2增加多了一個app=web的labels
[root@node-1 demo]# kubectl get nodes --show-labels 
NAME     STATUS   ROLES    AGE   VERSION   LABELS
node-1   Ready    master   15d   v1.15.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node-1,kubernetes.io/os=linux,node-role.kubernetes.io/master=
node-2   Ready    <none>   15d   v1.15.3   app=web,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node-2,kubernetes.io/os=linux
node-3   Ready    <none>   15d   v1.15.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node-3,kubernetes.io/os=linux
  1. 通過nodeSelector將pod調度到app=web所屬的labels
[root@node-1 demo]# cat nginx-nodeselector.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-run-on-nodeselector
  annotations:
    kubernetes.io/description: "Running the Pod on specific node by nodeSelector"
spec:
  containers:
  - name: nginx-run-on-nodeselector
    image: nginx:latest
    ports:
    - name: http-80-port
      protocol: TCP
      containerPort: 80 
  nodeSelector:     #通過nodeSelector將pod調度到特定的labels
    app: web
  1. 應用yaml文件生成pod
[root@node-1 demo]# kubectl apply -f nginx-nodeselector.yaml 
pod/nginx-run-on-nodeselector created
  1. 檢查驗證pod的運行情況,已經運行在node-2節點
[root@node-1 demo]# kubectl get pods nginx-run-on-nodeselector -o wide 
NAME                        READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
nginx-run-on-nodeselector   1/1     Running   0          51s   10.244.1.24   node-2   <none>           <none>

系統默認預先定義有多種內置的labels,這些labels可以標識node的屬性,如arch架構,操作系統類型,主機名等

  • beta.kubernetes.io/arch=amd64
  • beta.kubernetes.io/os=linux
  • kubernetes.io/arch=amd64
  • kubernetes.io/hostname=node-3
  • kubernetes.io/os=linux

1.3 node Affinity and anti-affinity

affinity/anti-affinity和nodeSelector功能相類似,相比於nodeSelector,affinity的功能更加豐富,未來會取代nodeSelector,affinity增加了如下的一些功能增強:

  • 表達式更加豐富,匹配方式支持多樣,如In,NotIn, Exists, DoesNotExist. Gt, and Lt;
  • 可指定soft和preference規則,soft表示需要滿足的條件,通過requiredDuringSchedulingIgnoredDuringExecution來設置,preference則是優選選擇條件,通過preferredDuringSchedulingIgnoredDuringExecution指定
  • affinity提供兩種級別的親和和反親和:基於node的node affinity和基於pod的inter-pod affinity/anti-affinity,node affinity是通過node上的labels來實現親和力的調度,而pod affinity則是通過pod上的labels實現親和力的調度,兩者作用的範圍有所不同。

下面通過一個例子來演示node affinity的使用,requiredDuringSchedulingIgnoredDuringExecution指定需要滿足的條件,preferredDuringSchedulingIgnoredDuringExecution指定優選的條件,兩者之間取與關係。

  1. 查詢node節點的labels,默認包含有多個labels,如kubernetes.io/hostname
[root@node-1 ~]# kubectl get nodes --show-labels 
NAME  STATUS  ROLES AGE  VERSION  LABELS
node-1  Ready master  15d  v1.15.3  beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node-1,kubernetes.io/os=linux,node-role.kubernetes.io/master=
node-2  Ready <none>  15d  v1.15.3  app=web,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node-2,kubernetes.io/os=linux
node-3  Ready <none>  15d  v1.15.3  beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node-3,kubernetes.io/os=linux
  1. 通過node affiinity實現調度,通過requiredDuringSchedulingIgnoredDuringExecution指定滿足條件kubernetes.io/hostname爲node-2和node-3,通過preferredDuringSchedulingIgnoredDuringExecution優選條件需滿足app=web的labels
[root@node-1 demo]# cat nginx-node-affinity.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-run-node-affinity
  annotations:
    kubernetes.io/description: "Running the Pod on specific node by node affinity"
spec:
  containers:
  - name: nginx-run-node-affinity
    image: nginx:latest
    ports:
    - name: http-80-port
      protocol: TCP
      containerPort: 80 
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - node-1
            - node-2
            - node-3
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: app
            operator: In
            values: ["web"] 
  1. 應用yaml文件生成pod
[root@node-1 demo]# kubectl apply -f nginx-node-affinity.yaml 
pod/nginx-run-node-affinity created
  1. 確認pod所屬的node節點,滿足require和 preferre條件的節點是node-2
[root@node-1 demo]# kubectl get pods --show-labels nginx-run-node-affinity -o wide 
NAME                      READY   STATUS    RESTARTS   AGE    IP            NODE     NOMINATED NODE   READINESS GATES   LABELS
nginx-run-node-affinity   1/1     Running   0          106s   10.244.1.25   node-2   <none>           <none>            <none>

寫在最後

本文介紹了kubernetes中的調度機制,默認創建pod是全自動調度機制,調度由kube-scheduler實現,調度過程分爲兩個階段調度階段(過濾和沉重排序)和綁定階段(在node上運行pod)。通過干預有四種方式:

  1. 指定nodeName
  2. 通過nodeSelector
  3. 通過node affinity和anti-affinity
  4. 通過pod affinity和anti-affinity

附錄

調度框架介紹:https://kubernetes.io/docs/concepts/configuration/scheduling-framework/

Pod調度方法:https://kubernetes.io/docs/concepts/configuration/assign-pod-node/


當你的才華撐不起你的野心時,你就應該靜下心來學習

返回kubernetes系列教程目錄

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章