全部產品
Search
文件中心

Container Service for Kubernetes:實現ECI Pod可用性區域打散以及親和調度

更新時間:Jun 19, 2024

高可用以及高效能是分布式任務執行過程中的重要要求。在ACK叢集Pro版中,您可以通過Kubernetes原生調度語義實現分布式任務的跨可用性區域打散,以達到高可用性區域部署的要求,或者通過Kubernetes原生調度語義實現分布式任務在指定可用性區域中的親和性部署,以達到高效能部署的要求。

前提條件

  • 已建立ACK叢集Pro版,且叢集版本為v1.20及以上。具體操作,請參見建立Kubernetes託管版叢集

  • 已確保ACK叢集Pro版中Kube Scheduler組件版本滿足以下要求。

    ACK叢集Pro版版本

    Kube Scheduler最低版本要求

    1.28

    1.28.3-aliyun-5.9

    1.26

    1.26.3-aliyun-5.9

    1.24

    1.24.6-aliyun-5.9

    1.22

    1.22.15-aliyun-5.9

    低於1.22

    說明

    為了實現ECI Pod可用性區域打散以及親和調度,請升級ACK叢集

    不支援

    說明

    為實現ECI Pod可用性區域打散以及親和調度,請升級Kube Scheduler組件。相關操作,請參見kube-scheduler

  • 調度ECI Pod時,已在ECI Profile中配置當前期望調度的目標可用性區域vSwitch。具體操作,請參見配置eci-profile

  • 已確保Pod中帶有nodeAffinitypodAffinitytopologySpreadConstraints欄位或存在匹配的ResourcePolicy。

    說明

    若您希望Pod能夠調度到Arm架構的Virtual Node上,需要在Pod上添加對應汙點的汙點容忍欄位tolerations

  • 開啟叢集虛擬節點調度策略,且叢集版本、組件版本符合要求。

注意事項

  • 調度ECI Pod時,目前僅支援設定topologyKeytopology.kubernetes.io/zone

  • 調度ECI Pod時,不支援通過Annotation的方式設定ECI Pod的vSwitch順序。當Pod聲明了vSwitch順序時,該功能將被自動禁用。

  • 調度ECI Pod不支援與FastFailed模式同時使用。當Pod申明了FastFailed模式時,該功能將被自動禁用。

相關概念

關於打散部署以及親和部署的詳細說明,請參見官方文檔拓撲分布約束將Pod指派給節點。相關術語說明,請參見NodeAffinityPodAffinitymaxSkew

實現ECI Pod可用性區域打散以及親和調度

下文將在v1.22版本的ACK叢集Pro版中示範ECI Pod可用性區域打散以及親和調度功能。

樣本一:通過拓撲分布約束(Topology Spread Constraints)實現跨可用性區域打散

  1. 在工作負載申明中增加拓撲分布約束。

    Pod的Spec欄位中或Deployment、Job等工作負載的PodTemplate的Spec欄位中,可以通過以下方式申明一個拓撲分布約束。

      topologySpreadConstraints:
        - maxSkew: <integer>
          minDomains: <integer> # 可選,從v1.25開始成為Beta。
          topologyKey: <string>
          whenUnsatisfiable: <string>
          labelSelector: <object>
          matchLabelKeys: <list> # 可選,從v1.27開始成為Beta。
          nodeAffinityPolicy: [Honor|Ignore] # 可選,從v1.26開始成為Beta。
          nodeTaintsPolicy: [Honor|Ignore] # 可選,從v1.26開始成為Beta。

    本樣本將建立一個在多個可用性區域上均勻分布的Deployment。以下為該Deployment的YAML檔案。

    展開查看YAML檔案

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: with-pod-topology-spread
      labels:
        app: with-pod-topology-spread
    spec:
      replicas: 10
      selector:
        matchLabels:
          app: with-pod-topology-spread
      template:
        metadata:
          labels:
            app: with-pod-topology-spread
        spec:
          affinity:
            nodeAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - weight: 1
                preference:
                  matchExpressions:
                  - key: type
                    operator: NotIn
                    values:
                    - virtual-kubelet
          topologySpreadConstraints:
            - maxSkew: 1
              topologyKey: topology.kubernetes.io/zone
              whenUnsatisfiable: DoNotSchedule
              labelSelector:
                matchLabels:
                  app: with-pod-topology-spread
          tolerations:
            - key: "virtual-kubelet.io/provider"
              operator: "Exists"
              effect: "NoSchedule"
          containers:
          - name: with-pod-topology-spread
            image: registry.k8s.io/pause:2.0
            resources:
              requests:
                cpu: "1"
                memory: "256Mi"

    參數

    說明

    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 1
      preference:
        matchExpressions:
        - key: type
          operator: NotIn
          values:
          - virtual-kubelet

    表示Pod將優先被調度到ECS節點上。

    關於參數的詳細資料,請參見節點親和性

    topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: with-pod-topology-spread

    表示Pod必須在多個可用性區域上均勻部署。

    關於參數的詳細資料,請參見topologySpreadConstraints欄位

    tolerations:
      - key: "virtual-kubelet.io/provider"
        operator: "Exists"
        effect: "NoSchedule"

    調度器容忍了Virtual Node上的汙點,使得Pod能夠被調度到Virtual Node上。

    關於參數的詳細資料,請參見容忍度

    說明

    若您希望Pod能夠調度到Arm架構的Virtual Node上,需要在Pod上添加對應汙點的汙點容忍。

  2. 建立工作負載。

    將上面的代碼儲存為deployment.yaml,並執行以下命令部署Deployment。

    kubectl apply -f deployment.yaml
  3. 驗證工作負載調度結果。

    • 通過以下命令查看生產出的Pod所在的節點。

      kubectl get po -lapp=with-pod-topology-spread -ocustom-columns=NAME:.metadata.name,NODE:.spec.nodeName --no-headers | grep -v "<none>"
    • 通過以下命令查看生產出的Pod在各個可用性區域中的數量。

      kubectl get po -lapp=with-pod-topology-spread -ocustom-columns=NODE:.spec.nodeName --no-headers | grep -v "<none>" | xargs -I {} kubectl get no {} -ojson | jq '.metadata.labels["topology.kubernetes.io/zone"]' | sort | uniq -c

樣本二:通過nodeAffinity和podAffinity實現可用性區域親和

  1. 在工作負載申明中增加親和性約束。

    本樣本將建立在單個可用性區域上聚集分布的Deployment。以下為該Deployment的YAML檔案。

    展開查看YAML檔案

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: with-affinity
      labels:
        app: with-affinity
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: with-affinity
      template:
        metadata:
          labels:
            app: with-affinity
        spec:
          affinity:
            podAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
              - labelSelector:
                  matchExpressions:
                  - key: app
                    operator: In
                    values:
                    - with-affinity
                topologyKey: topology.kubernetes.io/zone
            nodeAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - weight: 1
                preference:
                  matchExpressions:
                  - key: type
                    operator: NotIn
                    values:
                    - virtual-kubelet
          tolerations:
            - key: "virtual-kubelet.io/provider"
              operator: "Exists"
              effect: "NoSchedule"
          containers:
          - name: with-affinity
            image: registry.k8s.io/pause:2.0

    參數

    說明

    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - with-affinity
    		topologyKey: topology.kubernetes.io/zone

    表示Pod必須部署在單個可用性區域上。

    關於參數的詳細資料,請參見節點親和性

    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: type
            operator: NotIn
            values:
            - virtual-kubelet

    表示Pod將優先被調度到ECS節點上。

    關於參數的詳細資料,請參見節點親和性

    tolerations:
      - key: "virtual-kubelet.io/provider"
        operator: "Exists"
        effect: "NoSchedule"

    調度器容忍了Virtual Node上的汙點,使得Pod能夠被調度到Virtual Node上。

    關於參數的詳細資料,請參見容忍度

    若您希望指定可用性區域進行部署,可以將樣本中的podAffinity刪去,在nodeAffinity添加如下約束。下方約束表明Pod必須在可用性區域cn-beijing-a上進行部署。

    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: topology.kubernetes.io/zone
          operator: In
          values:
          - cn-beijing-a
  2. 建立工作負載。

    將上面的代碼儲存為deployment.yaml,並執行以下命令部署Deployment。

    kubectl apply -f deployment.yaml
  3. 驗證工作負載調度結果。

    • 通過以下命令查看生產出的Pod所在的節點。

      kubectl get po -lapp=with-affinity -ocustom-columns=NAME:.metadata.name,NODE:.spec.nodeName --no-headers | grep -v "<none>"
    • 通過以下命令查看生產出的Pod在各個可用性區域中的數量。

      kubectl get po -lapp=with-affinity -ocustom-columns=NODE:.spec.nodeName --no-headers | grep -v "<none>" | xargs -I {} kubectl get no {} -ojson | jq '.metadata.labels["topology.kubernetes.io/zone"]' | sort | uniq -c

ECI嚴格拓扑打散功能介紹

在保持預設狀態不變的情況下,當配置了強制打散約束時,Scheduler會將所有Pod均勻放置到所有可用性區域上,但並不考慮ECI Pod的生產結果。如下圖所示,假設將打散功能的maxSkew設定為1。關於maxSkew,請參見maxSkew

此時若可用性區域B和C中生產ECI Pod失敗,則可用性區域A上會放置2個ECI Pod,其他兩個可用性區域沒有ECI Pod,從而破壞打散功能的maxSkew約束。

當嚴格拓扑打散功能開啟後,在ACK Pro版叢集中,調度器將嚴格保證Pod的強制打散需求得到滿足。Scheduler會在可用性區域A、B、C上各放置1個Pod,剩下的Pod將處於Pending狀態,等待現有Pod生產,如下圖所示。

當PodA1生產成功後,Pending狀態的Pod將繼續Pending,這是由於可用性區域B以及可用性區域C上的ECI Pod仍然可能生產失敗,Pod放置於任意可用性區域仍然可能導致生產結束後破壞maxSkew約束。當PodB1生產成功後,Scheduler將會放置一個Pod在可用性區域C。如下圖所示,其中綠色背景的Pod為生產完成的Pod。

若您不需要嚴格拓扑打散功能,請將拓扑打散約束中的調度條件whenUnsatisfiable設定為ScheduleAnyway。詳細資料,請參見分布約束定義