Kubernetes 調度器和調度過程

一、Scheduler

當Scheduler通過API server 的watch接口監聽到新建Pod副本的信息後,它會檢查所有符合該Pod要求的Node列表,開始執行Pod調度邏輯。調度成功後將Pod綁定到目標節點上。Scheduler在整個系統中承擔了承上啓下的作用,承上是負責接收創建的新Pod,爲安排一個落腳的地(Node),啓下是安置工作完成後,目標Node上的kubelet服務進程接管後繼工作,負責Pod生命週期的後半生。具體來說,Scheduler的作用是將待調度的Pod安裝特定的調度算法和調度策略綁定到集羣中的某個合適的Node上,並將綁定信息傳給API server 寫入etcd中。整個調度過程中涉及三個對象,分別是:待調度的Pod列表,可以的Node列表,以及調度算法和策略。

Kubernetes Scheduler 提供的調度流程分三步:

1)預選策略(predicate) 遍歷nodelist,選擇出符合要求的候選節點,Kubernetes內置了多種預選規則供用戶選擇;

2)優選策略(priority) 在選擇出符合要求的候選節點中,採用優選規則計算出每個節點的積分,最後選擇得分最高的;

3)選定(select)  如果最高得分有好幾個節點,select就會從中隨機選擇一個節點。

1.常用的預選策略

  • CheckNodeConditionPred  檢查節點是否正常
  • GeneralPred  HostName(如果pod定義hostname屬性,會檢查節點是否匹配。pod.spec.hostname)、PodFitsHostPorts(檢查pod要暴露的hostpors是否被佔用。pod.spec.containers.ports.hostPort)
  • MatchNodeSelector  pod.spec.nodeSelector  看節點標籤能否適配pod定義的nodeSelector
  • PodFitsResources 判斷節點的資源能夠滿足Pod的定義(如果一個pod定義最少需要2C4G node上的低於此資源的將不被調度。用kubectl describe node NODE名稱 可以查看資源使用情況)
  • NoDiskConflict 判斷pod定義的存儲是否在node節點上使用。(默認沒有啓用)
  • PodToleratesNodeTaints 檢查pod上Tolerates的能否容忍污點(pod.spec.tolerations)
  • CheckNodeLabelPresence 檢查節點上的標誌是否存在 (默認沒有啓動)
  • CheckServiceAffinity  根據pod所屬的service。將相同service上的pod儘量放到同一個節點(默認沒有啓動)
  • CheckVolumeBinding 檢查是否可以綁定(默認沒有啓動)
  • NoVolumeZoneConflict 檢查是否在一起區域(默認沒有啓動)
  • CheckNodeMemoryPressure  檢查內存是否存在壓力
  • CheckNodeDiskPressure   檢查磁盤IO壓力是否過大
  • CheckNodePIDPressure 檢查pid資源是否過大

2.常用的優選策略

  • least_requested  選擇消耗最小的節點(根據空閒比率評估 cpu(總容量-sum(已使用)*10/總容量) )
  • balanced_resource_allocation  從節點列表中選出各項資源使用率最均衡的節點(CPU和內存)
  • node_prefer_avoid_pods  節點傾向
  • taint_toleration 將pod對象的spec.toleration與節點的taints列表項進行匹配度檢查,匹配的條目越多,得分越低。
  • selector_spreading 與services上其他pod儘量不在同一個節點上,節點上通一個service的pod越少得分越高。
  • interpod_affinity  遍歷node上的親和性條目,匹配項越多的得分越高
  • most_requested  選擇消耗最大的節點上(儘量將一個節點上的資源用完)
  • node_label  根據節點標籤得分,存在標籤既得分,沒有標籤沒得分。標籤越多 得分越高。
  • image_locality  節點上有所需要的鏡像既得分,所需鏡像越多得分越高。(根據已有鏡像體積大小之和)

四、高級調度方式

  • 節點選擇器: nodeSelector、nodeName
  • 節點親和性調度: nodeAffinity
  • Pod親和性調度:PodAffinity
  • Pod反親和性調度:podAntiAffinity

1.nodeSelector

我們定義一個pod,讓其選擇帶有node=ssd這個標籤的節點

# cat > test.yaml<<EOF
apiVersion: v1
kind: Pod
metadata:
  name: pod-1
  labels:
    name: myapp
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
  nodeSelector:
    node: ssd
EOF

# kubectl create -f test.yaml

查看信息

//get一下pod 一直處於Pending狀態
# kubectl get pod 
NAME      READY     STATUS    RESTARTS   AGE
pod-1     0/1       Pending   0          7s

//查看詳細信息,是沒有可用的selector
# kubectl describe pod pod-1
...
Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  9s (x14 over 36s)  default-scheduler  0/4 nodes are available: 4 node(s) didn't match node selector.

//我們給node2打上這個標籤
# kubectl label node k8s-node02 node=ssd
node/k8s-node02 labeled

//Pod正常啓動
#  kubectl describe pod pod-1
....
Events:
  Type     Reason            Age                From                 Message
  ----     ------            ----               ----                 -------
  Warning  FailedScheduling  2m (x122 over 8m)  default-scheduler    0/4 nodes are available: 4 node(s) didn't match node selector.
  Normal   Pulled            7s                 kubelet, k8s-node02  Container image "ikubernetes/myapp:v1" already present on machine
  Normal   Created           7s                 kubelet, k8s-node02  Created container
  Normal   Started           7s                 kubelet, k8s-node02  Started container

2.nodeAffinity

kubectl explain pod.spec.affinity.nodeAffinity

1)requiredDuringSchedulingIgnoredDuringExecution 硬親和性  必須滿足親和性。

  • matchExpressions  匹配表達式,這個標籤可以指定一段,例如pod中定義的key爲zone,operator爲In(包含那些),values爲 foo和bar。就是在node節點中包含foo和bar的標籤中調度
  • matchFields  匹配字段 和上面的意思 不過他可以不定義標籤值,可以定義

2)preferredDuringSchedulingIgnoredDuringExecution   軟親和性 能滿足最好,不滿足也沒關係。

  • preference 優先級
  • weight 權重1-100範圍內,對於滿足所有調度要求的每個節點,調度程序將通過迭代此字段的元素計算總和,並在節點與對應的節點匹配時將“權重”添加到總和。

運算符包含:In,NotIn,Exists,DoesNotExist,Gt,Lt。可以使用NotIn和DoesNotExist實現節點反關聯行爲。

硬親和性:

# cat > pod-affinity-demo.yaml<<EOF
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-pod
  labels:
    name: myapp
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: zone
            operator: In
            values:
            - foo
            - bar
EOF

# kubectl apply -f pod-affinity-demo.yaml 
# kubectl describe pod node-affinity-pod 
.....
Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  33s (x25 over 1m)  default-scheduler  0/4 nodes are available: 4 node(s) didn't match node selector.

//給其中一個node打上foo的標籤
# kubectl label node k8s-node03 zone=foo
# kubectl get pods
NAME                READY     STATUS    RESTARTS   AGE
node-affinity-pod   1/1       Running   0          8m

軟親和性:
與requiredDuringSchedulingIgnoredDuringExecution比較,這裏需要注意的是preferredDuringSchedulingIgnoredDuringExecution是個列表項,而preference不是一個列表項了。

# cat > pod-affinity-demo.yaml<<EOF
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-pod-2
  labels:
    name: myapp
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 50
        preference:
          matchExpressions:
          - key: zone
            operator: In
            values:
            - foo
            - bar
EOF

# kubectl get pod -o wide 
NAME                  READY     STATUS    RESTARTS   AGE       IP           NODE
node-affinity-pod     1/1       Running   0          3h        10.244.3.2   k8s-node03
node-affinity-pod-2   1/1       Running   0          1m        10.244.3.3   k8s-node03

3.PodAffinity

Pod親和性場景,我們的k8s集羣的節點分佈在不同的區域或者不同的機房,當服務A和服務B要求部署在同一個區域或者同一機房的時候,我們就需要親和性調度了。

kubectl explain pod.spec.affinity.podAffinity 和NodeAffinity是一樣的,都是有硬親和性和軟親和性

硬親和性:

  • labelSelector  選擇跟那組Pod親和
  • namespaces 選擇哪個命名空間
  • topologyKey 指定節點上的哪個鍵
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-pod1
  labels:
    name: podaffinity-myapp
    tier: service
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
---
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-pod2
  labels:
    name: podaffinity-myapp
    tier: front
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: name
            operator: In
            values:
            - podaffinity-myapp
        topologyKey: kubernetes.io/hostname

查看信息

# kubectl get pods -o wide 
NAME                  READY     STATUS    RESTARTS   AGE       IP           NODE
node-affinity-pod1    1/1       Running   0          12s       10.244.2.6   k8s-node02
node-affinity-pod2    1/1       Running   0          12s       10.244.2.5   k8s-node02

4.podAntiAffinity 

Pod反親和性場景,當應用服務A和數據庫服務B要求儘量不要在同一臺節點上的時候。

kubectl explain pod.spec.affinity.podAntiAffinity 也分爲硬反親和性和軟反親和性調度(和podAffinity一樣的配置)

示例:

//首先把兩個node打上同一個標籤。
# kubectl label node k8s-node02 zone=foo 
# kubectl label node k8s-node03 zone=foo

//反硬親和調度
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-pod1
  labels:
    name: podaffinity-myapp
    tier: service
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
---
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-pod2
  labels:
    name: podaffinity-myapp
    tier: front
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: name
            operator: In
            values:
            - podaffinity-myapp
        topologyKey: zone

查看一下(因爲zone這個key在每個node都有會,所以第二個Pod沒有辦法調度,所以一直Pending狀態)

# kubectl get  pod 
NAME                 READY     STATUS    RESTARTS   AGE
node-affinity-pod1   1/1       Running   0          11s
node-affinity-pod2   0/1       Pending   0          11s

五、污點容忍調度(Taint和Toleration)

前兩種方式都是pod選擇那個pod,污點調度是node選擇的pod,污點就是定義在節點上的鍵值屬性數據。舉要作用是讓節點拒絕pod,拒絕不合法node規則的pod。Taint(污點)和 Toleration(容忍)是相互配合的,可以用來避免 pod 被分配到不合適的節點上,每個節點上都可以應用一個或多個 taint ,這表示對於那些不能容忍這些 taint 的 pod,是不會被該節點接受的。

1.Taint

Taint是節點上屬性,我們看一下Taints如何定義

kubectl explain node.spec.taints(對象列表)

  • key  定義一個key
  • value 定義一個值
  • effect  pod不能容忍這個污點時,他的行爲是什麼,行爲分爲三種:NoSchedule 僅影響調度過程,對現存的pod不影響。PreferNoSchedule 系統將盡量避免放置不容忍節點上污點的pod,但這不是必需的。就是軟版的NoSchedule  NoExecute 既影響調度過程,也影響現存的pod,不滿足的pod將被驅逐。

node 做taint標記:

//語法:kubectl taint NODE NAME KEY_1=VAL_1:TAINT_EFFECT_1 ... KEY_N=VAL_N:TAINT_EFFECT_N [options]

//增加taint
# kubectl  taint node k8s-node02 node-type=prod:NoSchedule

//刪除taint
# kubectl  taint node k8s-node02 node-type:NoSchedule-

2.Tolerations

  • key 被容忍的key
  • tolerationSeconds  被驅逐的寬限時間,默認是0 就是立即被驅逐
  • value  被容忍key的值
  • operator  Exists只要key在就可以調度,Equal(等值比較)必須是值要相同
  • effect  節點調度後的操作

示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      release: dev
  template:
    metadata:
      labels:
        app: myapp
        release: dev
    spec:
      containers:
      - name: myapp-containers
        image: ikubernetes/myapp:v2
        ports:
        - name: http
          containerPort: 80
      tolerations:
      - key: "node-type"
        operator: "Equal"
        value: "prod"
        effect: "NoSchedule"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章