Kubernetes 核心介紹 Scheduler

Posted by Alan Zhan on Monday, May 16, 2022

Scheduler 嚴格算起來,算是特殊的 Controller,工作原理與其他控制器無差別。

Scheduler 的特殊職責在於監控當前集群所有未調度的 Pod,並且獲取當前集群的所有節點健康狀況和資源使用情控,為待調度的 Pod 選擇最佳節點,完成調度。

kube-scheduler 負責分配調度 Pod 到集群內的節點上,他監聽 kube-apiserver ,查詢還未分配 Node 的 Pod ,然後根據調度策略為這些 Pod 分配節點 (更新 Pod 的 NodeName Field)。

設計 scheduler 需要要充分考慮諸多因素:

  • 公平調度
  • 資源高效利用
  • QoS(Quality of Service)
  • affinity 和 antiaffinity
  • 數據本地化 (data locality)
  • 內部負載干擾 (inter-workload interference)
  • deadlines

Scheduler

kube-scheduler 調度分為幾個階段:

  • predicate: 將所有節點拿出來,過濾不符合條件節點。
  • priority: 優先級排序,選擇優先級最高的節點。
  • Bind : 將計算節點與 Pod 綁定,完成調度。

Scheduling Cycle & Binding Cycle

Predicate 策略

這邊只有列出常見的策略,還有其他很多策略,你也可以編寫自己的策略。

  • PodFitsHostPorts: 檢查是否有 Host Ports 衝突。
  • PodFitsPorts: 同PodFitsHostPorts。
  • PodFitsResources: 檢查 Node 的資源是否充足,包括允許的 Pod 數量、CPU、內存、GPU 個數以及其他的 OpaqueIntResources。
  • Hostname: 檢查 pod.Spec.NodeName 是否與候選節點一致。
  • MatchNodeSelector: 檢查候選節點的 pod.Spec.NodeSelector 是否匹配。
  • NoVolumeZoneConflict: 檢查 volume zone 是否衝突。
  • MatchInterPodAffinity: 檢查是否匹配 Pod 的 affinity 要求。
  • NoDiskConflict: 檢查是否存在 Volume 衝突,僅用於 GCP PD 、 AWS EBS 、 Ceph RBD 以及 iSCSI 。
  • PodToleratesNodeTaints: 檢查 Pod 是否容忍 Node Taints。
  • CheckNodeMemoryPressure: 檢查 Pod 是否可以調度到 MemoryPressure 的節點上。
  • CheckNodeDiskPressure: 檢查 Pod 是否可以調度到 DiskPressure 的節點上。
  • NoVolumeNodeConflict: 檢查節點是否滿足 Pod 所引用的 Volume 的條件。

Priorites 策略

經過 Predicate 之後,就要去為剩下的機器打分數,然後排序。

  • SelectorSpreadPriority: 優先減少節點上屬於同一個 Service 或 Replication Controller 的 Pod 數量。
  • InterPodAffinityPriority: 優先將 Pod 調度到相同的拓樸上 (如同一個節點、Rack、Zone 等)。
  • LeastRequestedPriority: 優先調度到請求資源少的節點上。
  • BalancedResourceAllocation: 優先平衡各節點的資源使用。
  • NodePreferAvoidPodsPriority: alpha.kubernetes.io/perferAvoidPods 字段判斷,權重為 10000 ,避免其他優先即策略的影響。
  • NodeAffinitypriority: 優先調度到匹配 NodeAffinity 的節點上。
  • TaintTolerationPriority: 優先調度到匹配 TaintToleration 節點上。
  • ServiceSpreadingPriority: 盡量將同一個 service 的 Pod 分配到不同節點上,已經被 SelectorSpreadPriority 替代 (默認未使用)。
  • EqualPriority: 將所有節點的優先級設置為1 (默認未使用)。
  • ImageLocalityPriority: 盡量將使用大 Image 的容器調度到已經下拉的該 Image 的節點上 (默認未使用)。
  • MostRequestedPriority: 盡量調度到已經使用過的 Node 上,特別適用於 cluster0autoscaler (默認未使用)。

指定 Node 調度

可以通過 nodeSelector 、 nodeAffinity 、 podAffinity 以及 Taints 與 tolerations 等來將 Pod 調度到需要的 Node 上。

也可以指定設置 nodeName 參數,將 Pod 調度到指定 Node 節點上。

NodeSelector

可以在 pod 上面標記 nodeSelector ,讓在創建 pod 的時候調度到打有對應的 key 與 value 的機器上。

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

NodeAffinity

NodeAffinity 目前支援兩種

  • requiredDuringSchedulingIgnoredDuringExecution: 必須滿足條件。
  • preferedDuringSchedulingIgnoredDuringExecution: 優選條件。
apiVersion: v1
kind: Pod
metadata:
  name: with-affinity-anti-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/os
            operator: In
            values:
            - linux
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: label-1
            operator: In
            values:
            - key-1
      - weight: 50
        preference:
          matchExpressions:
          - key: label-2
            operator: In
            values:
            - key-2
  containers:
  - name: with-node-affinity
    image: k8s.gcr.io/pause:2.0

PodAffinity

PodAffinity 基於 Pod 的標籤來選擇 Node,僅調度滿足條件 Pod 所在的 Node 上,支持 PodAffinity 和 PodAntiffinity。

  • requiredDuringSchedulingIgnoredDuringExecution: 必須滿足條件。
  • preferedDuringSchedulingIgnoredDuringExecution: 優選條件。
apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: topology.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: topology.kubernetes.io/hostname
  containers:
  - name: with-pod-affinity
    image: k8s.gcr.io/pause:2.0

Taints 和 Tolerations

在使用 NodeSelector 的場景下,是不會強制可以拒絕 Pod 調度到某些 Node 上的,或者是在初步規劃 kubernetes 時,沒有考慮到會有所有部門都會使用 Kubernetes 的技術,結果後面大家都上 k8s 導致需要為某些節點做牆隔離,為了解決這些問題,所以可以使用 Taints 和 Tolerations。

Taint 和 Tolerations 用於保證 Pod 不會被調度到不合適的 Node 上,其中 Taint 應用於 Node 上,而 Toleration 則應用在 Pod 上。

目前支持的 Taint 類型:

  • NoSchedule: 新的 Pod 不會被調度到該節點上,不影響正在運行的 Pod。
  • PreferNoSchedule: Soft 版的 NoSchedule ,盡量不調度到該 Node 上。
  • NoExecute: 新的 Pod 不調度到該 Node 上,並且刪除 (evict) 已經在運行的 Pod。Pod 可以增加一個時間 (tolerationSecondes)。

然而,當 Pod 與 Toleration 匹配 Node 的所有 Taints 的時候,可以調度到該 Node 上,當 Pod 是已經運行的時候,也不會被刪除 (evicted)。

在 kubernets 內,當一個節點有問題的時候,他也是通過 taints 的機制,將機器打上 key value,以確保不會在有 pod 不會再被調度上去,並且打上 tolerationSecondes 確保在一訂時間內恢復的話, pod 是不會被驅逐的。

PriorityClass

從 v1.8 開始,kube-scheduler 支持定義 Pod 的優先級,從而保證高優先級的 Pod 優先調度。

preemptionPolicy:

  • PreemptLowerPriority: 將允許該 PriorityClass 的 Pod 搶占較低優先級的 Pod 。
  • Never: 非搶佔式。
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
preemptionPolicy: Never
globalDefault: false
description: "This priority class should be used for XYZ service pods only."

多調度器

如果默認的調度器不滿足需求,還可以部屬自定義的調度器。並且在整個集群中,同時可以運行多個調度器實例,通過 pod.spec.schedulerName 來選擇使用哪一個調度器 (默認使用內置的調度器)。

總結

對於 k8s 整體運作原理已經開始有更深入的認識了,期待自己早日搞懂 k8s 。

歡迎到我的 Facebook Alan 的筆記本 留言,順手給我個讚吧!你的讚將成為我持續更新的動力,感謝你的閱讀,讓我們一起學習成為更好的自己。