全部產品
Search
文件中心

Container Service for Kubernetes:使用Capacity Scheduling

更新時間:Jun 19, 2024

通過Kubernetes原生的ResourceQuota方式進行固定資源分派,叢集的整體資源使用率不高。阿里雲借鑒Yarn Capacity Scheduling的設計思路,基於Scheduling Framework的擴充機制,在調度時引入彈性配額組實現了Capacity Scheduling功能,在確保使用者資源分派的基礎上通過資源共用的方式來提升叢集的整體資源使用率。本文介紹如何使用Capacity Scheduling功能。

前提條件

已建立Kubernetes版本大於等於1.20的ACK叢集Pro版。詳細資料,請參見建立Kubernetes託管版叢集

背景資訊

當叢集中有多個使用者時,為了保障使用者有足夠的資源使用,管理員會將叢集的資源固定分配給不同的使用者。傳統的方法是通過Kubernetes原生的ResourceQuota方式進行固定資源的分配。因為不同的使用者使用資源的周期和方式不同,可能會出現在某一時刻,一些使用者的資源不夠用,而另一些使用者的資源閑置。如果出現多個類似的情況,則整個叢集會有很多資源浪費,導致叢集的整體資源使用率下降。

Capacity Scheduling核心功能

針對上述問題,阿里雲基於Scheduling Framework的擴充機制,在調度側實現了Capacity Scheduling的功能,在確保使用者的資源分派的基礎上通過資源共用的方式來提升整體資源的利用率。Capacity Scheduling具有以下功能:

  • 支援定義不同層級的資源配額。如下圖所示,您可以根據具體情況(比如:公司的組織圖)配置多個層級的彈性配額。彈性配額組的葉子節點可以對應多個Namespace,但同一個Namespace只能歸屬於一個葉子節點。37

  • 支援不同彈性配額之間的資源借用和回收。

    • Min:您可以使用的保障資源(Guaranteed Resource)。當整個叢集資源緊張時,所有使用者使用的Min總和需要小於叢集的總資源量。

    • Max:您可以使用的資源上限。39

    說明
    • 您的工作負載可以向其他使用者借用其未使用的資源額度,但借用後可使用的資源總量依然不能超過Max。

    • 您未使用的Min資源配額可以被其他使用者借用,但當該使用者需要使用資源時,可以通過搶佔的方式回收借出的資源。

  • 支援多種資源的配置。您除了可以配置CPU和記憶體資源,也可以配置如GPU等任何Kubernetes支援的擴充資源(Extended Resource)。

使用Capacity scheduling功能的使用樣本

本文測試叢集節點資源為1台ecs.sn2.13xlarge機器(56 vCPU 224 GiB)。

  1. 執行以下命令,建立對應的Namespace。

    kubectl create ns namespace1
    kubectl create ns namespace2
    kubectl create ns namespace3
    kubectl create ns namespace4
  2. 使用以下YAML檔案範例,建立相應的彈性配額組。

    展開查看YAML檔案

    apiVersion: scheduling.sigs.k8s.io/v1beta1
    kind: ElasticQuotaTree
    metadata:
      name: elasticquotatree
      namespace: kube-system # 只在kube-system下才會生效
    spec:
      root:
        name: root # Root節點的Max必須等於Min
        max:
          cpu: 40
          memory: 40Gi
          nvidia.com/gpu: 4
        min:
          cpu: 40
          memory: 40Gi
          nvidia.com/gpu: 4
        children: # 配置第二級
          - name: root.a
            max:
              cpu: 40
              memory: 40Gi
              nvidia.com/gpu: 4
            min:
              cpu: 20
              memory: 20Gi
              nvidia.com/gpu: 2
            children: # 配置第三級
              - name: root.a.1
                namespaces: # 配置對應的Namespace
                  - namespace1
                max:
                  cpu: 20
                  memory: 20Gi
                  nvidia.com/gpu: 2
                min:
                  cpu: 10
                  memory: 10Gi
                  nvidia.com/gpu: 1
              - name: root.a.2
                namespaces: # 配置對應的Namespace
                  - namespace2
                max:
                  cpu: 20
                  memory: 40Gi
                  nvidia.com/gpu: 2
                min:
                  cpu: 10
                  memory: 10Gi
                  nvidia.com/gpu: 1
          - name: root.b
            max:
              cpu: 40
              memory: 40Gi
              nvidia.com/gpu: 4
            min:
              cpu: 20
              memory: 20Gi
              nvidia.com/gpu: 2
            children: # 配置第三級
              - name: root.b.1
                namespaces: # 配置對應的Namespace
                  - namespace3
                max:
                  cpu: 20
                  memory: 20Gi
                  nvidia.com/gpu: 2
                min:
                  cpu: 10
                  memory: 10Gi
                  nvidia.com/gpu: 1
              - name: root.b.2
                namespaces: # 配置對應的Namespace
                  - namespace4
                max:
                  cpu: 20
                  memory: 20Gi
                  nvidia.com/gpu: 2
                min:
                  cpu: 10
                  memory: 10Gi
                  nvidia.com/gpu: 1

    根據以上YAML檔案樣本配置,在namespaces欄位配置對應的命名空間,在children欄位配置對應子級的彈性配額。配置需要滿足以下幾點:

    • 同一個彈性配額中的Min≤Max。

    • 子級彈性配額的Min之和≤父級的Min。

    • Root節點的Min=Max≤叢集總資源。

    • Namespace只與彈性配額的葉子節點有一對多的對應關係,且同一個Namespace只能歸屬於一個葉子節點。

  3. 執行以下命令,查看彈性配額組是否建立成功。

    kubectl get ElasticQuotaTree -n kube-system

    預期輸出:

    NAME               AGE
    elasticquotatree   68s
  4. 使用以下YAML檔案範例,在namespace1中部署服務,Pod的副本數為5個,每個Pod請求CPU資源量為5核。

    展開查看YAML檔案

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx1
      namespace: namespace1
      labels:
        app: nginx1
    spec:
      replicas: 5
      selector:
        matchLabels:
          app: nginx1
      template:
        metadata:
          name: nginx1
          labels:
            app: nginx1
        spec:
          containers:
          - name: nginx1
            image: nginx
            resources:
              limits:
                cpu: 5
              requests:
                cpu: 5
  5. 執行以下命令,查看叢集Pod的部署情況。

    kubectl get pods -n namespace1

    預期輸出:

    NAME                     READY   STATUS    RESTARTS   AGE
    nginx1-744b889544-52dbg   1/1     Running   0          70s
    nginx1-744b889544-6l4s9   1/1     Running   0          70s
    nginx1-744b889544-cgzlr   1/1     Running   0          70s
    nginx1-744b889544-w2gr7   1/1     Running   0          70s
    nginx1-744b889544-zr5xz   0/1     Pending   0          70s
    • 因為當前叢集的資源有空閑(root.max.cpu=40),當在namespace1下的Pod申請CPU資源量超過root.a.1設定的min.cpu=10時,還可以繼續借用其他處於閒置資源,最多可以申請使用root.a.1設定的配額max.cpu=20

    • 當Pod申請CPU資源量超過max.cpu=20時,再申請的Pod會處於Pending狀態。所以此時申請的5個Pod中,有4個處於Running狀態,1個處於Pending狀態。

  6. 使用以下YAML檔案範例,在namespace2中部署服務,其中Pod的副本數為5個,每個Pod請求CPU資源量為5核。

    展開查看YAML檔案

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx2
      namespace: namespace2
      labels:
        app: nginx2
    spec:
      replicas: 5
      selector:
        matchLabels:
          app: nginx2
      template:
        metadata:
          name: nginx2
          labels:
            app: nginx2
        spec:
          containers:
          - name: nginx2
            image: nginx
            resources:
              limits:
                cpu: 5
              requests:
                cpu: 5
  7. 執行以下命令,查看叢集Pod的部署情況。

    kubectl get pods -n namespace1

    預期輸出:

    NAME                     READY   STATUS    RESTARTS   AGE
    nginx1-744b889544-52dbg   1/1     Running   0          111s
    nginx1-744b889544-6l4s9   1/1     Running   0          111s
    nginx1-744b889544-cgzlr   1/1     Running   0          111s
    nginx1-744b889544-w2gr7   1/1     Running   0          111s
    nginx1-744b889544-zr5xz   0/1     Pending   0          111s
    kubectl get pods -n namespace2

    預期輸出:

    NAME                     READY   STATUS    RESTARTS   AGE
    nginx2-556f95449f-4gl8s   1/1     Running   0          111s
    nginx2-556f95449f-crwk4   1/1     Running   0          111s
    nginx2-556f95449f-gg6q2   0/1     Pending   0          111s
    nginx2-556f95449f-pnz5k   1/1     Running   0          111s
    nginx2-556f95449f-vjpmq   1/1     Running   0          111s
    • nginx1一樣,因為當前叢集有資源空閑(root.max.cpu=40),當在namespace2下Pod申請CPU資源量超過root.a.2設定的min.cpu=10時,還可以繼續借用其他處於閒置資源,最多可以申請使用root.a.2設定的配額max.cpu=20

    • 當Pod申請CPU資源量超過max.cpu=20時,再申請的Pod處於Pending狀態。所以此時申請的5個Pod中,有4個處於Running狀態,1個處於Pending狀態。

    • 此時叢集中namespace1namespace2中的Pod所佔用的資源已經為root設定的root.max.cpu=40

  8. 使用以下YAML檔案範例,在namespace3中部署服務,其中Pod的副本數為5個,每個Pod請求CPU資源量為5核。

    展開查看YAML檔案

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx3
      namespace: namespace3
      labels:
        app: nginx3
    spec:
      replicas: 5
      selector:
        matchLabels:
          app: nginx3
      template:
        metadata:
          name: nginx3
          labels:
            app: nginx3
        spec:
          containers:
          - name: nginx3
            image: nginx
            resources:
              limits:
                cpu: 5
              requests:
                cpu: 5
  9. 執行以下命令,查看叢集Pod的部署情況。

    kubectl get pods -n namespace1

    預期輸出:

    NAME                      READY   STATUS    RESTARTS   AGE
    nginx1-744b889544-52dbg   1/1     Running   0          6m17s
    nginx1-744b889544-cgzlr   1/1     Running   0          6m17s
    nginx1-744b889544-nknns   0/1     Pending   0          3m45s
    nginx1-744b889544-w2gr7   1/1     Running   0          6m17s
    nginx1-744b889544-zr5xz   0/1     Pending   0          6m17s
    kubectl get pods -n namespace2

    預期輸出:

    NAME                      READY   STATUS    RESTARTS   AGE
    nginx2-556f95449f-crwk4   1/1     Running   0          4m22s
    nginx2-556f95449f-ft42z   1/1     Running   0          4m22s
    nginx2-556f95449f-gg6q2   0/1     Pending   0          4m22s
    nginx2-556f95449f-hfr2g   1/1     Running   0          3m29s
    nginx2-556f95449f-pvgrl   0/1     Pending   0          3m29s
    kubectl get pods -n namespace3

    預期輸出:

    NAME                     READY   STATUS    RESTARTS   AGE
    nginx3-578877666-msd7f   1/1     Running   0          4m
    nginx3-578877666-nfdwv   0/1     Pending   0          4m10s
    nginx3-578877666-psszr   0/1     Pending   0          4m11s
    nginx3-578877666-xfsss   1/1     Running   0          4m22s
    nginx3-578877666-xpl2p   0/1     Pending   0          4m10s

    nginx3的彈性配額root.b.1min設定為10,為了保障其設定的min資源,調度器會將root.a下之前借用root.b的Pod資源歸還,使得nginx3能夠至少得到配額min.cpu=10的資源量,保證其運行。

    調度器會綜合考慮root.a下作業的優先順序、可用性以及建立時間等因素,選擇相應的Pod歸還之前搶佔的資源(10核)。因此,nginx3得到配額min.cpu=10的資源量後,有2個Pod處於Running狀態,其他3個仍處於Pending狀態。

  10. 使用以下YAML檔案範例,在namespace4中部署服務nginx4,其中Pod的副本數為5個,每個Pod請求CPU資源量為5核。

    展開查看YAML檔案

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx4
      namespace: namespace4
      labels:
        app: nginx4
    spec:
      replicas: 5
      selector:
        matchLabels:
          app: nginx4
      template:
        metadata:
          name: nginx4
          labels:
            app: nginx4
        spec:
          containers:
          - name: nginx4
            image: nginx
            resources:
              limits:
                cpu: 5
              requests:
                cpu: 5
  11. 執行以下命令,查看叢集Pod的部署情況。

    kubectl get pods -n namespace1

    預期輸出:

    NAME                      READY   STATUS    RESTARTS   AGE
    nginx1-744b889544-cgzlr   1/1     Running   0          8m20s
    nginx1-744b889544-cwx8l   0/1     Pending   0          55s
    nginx1-744b889544-gjkx2   0/1     Pending   0          55s
    nginx1-744b889544-nknns   0/1     Pending   0          5m48s
    nginx1-744b889544-zr5xz   1/1     Running   0          8m20s
    kubectl get pods -n namespace2

    預期輸出:

    NAME                      READY   STATUS    RESTARTS   AGE
    nginx2-556f95449f-cglpv   0/1     Pending   0          3m45s
    nginx2-556f95449f-crwk4   1/1     Running   0          9m31s
    nginx2-556f95449f-gg6q2   1/1     Running   0          9m31s
    nginx2-556f95449f-pvgrl   0/1     Pending   0          8m38s
    nginx2-556f95449f-zv8wn   0/1     Pending   0          3m45s
    kubectl get pods -n namespace3

    預期輸出:

    NAME                     READY   STATUS    RESTARTS   AGE
    nginx3-578877666-msd7f   1/1     Running   0          8m46s
    nginx3-578877666-nfdwv   0/1     Pending   0          8m56s
    nginx3-578877666-psszr   0/1     Pending   0          8m57s
    nginx3-578877666-xfsss   1/1     Running   0          9m8s
    nginx3-578877666-xpl2p   0/1     Pending   0          8m56s
    kubectl get pods -n namespace4

    預期輸出:

    nginx4-754b767f45-g9954   1/1     Running   0          4m32s
    nginx4-754b767f45-j4v7v   0/1     Pending   0          4m32s
    nginx4-754b767f45-jk2t7   0/1     Pending   0          4m32s
    nginx4-754b767f45-nhzpf   0/1     Pending   0          4m32s
    nginx4-754b767f45-tv5jj   1/1     Running   0          4m32s

    同理,nginx4的彈性配額root.b.2min設定為10,為了保障其設定的min資源,調度器會將root.a下之前借用root.b的Pod資源歸還,使得nginx4能夠至少得到配額min.cpu=10的資源量,保證其運行。

    調度器會綜合考慮root.a下作業的優先順序、可用性以及建立時間等因素,選擇相應的Pod歸還之前搶佔的資源(10核)。因此,nginx4得到配額min.cpu=10資源量後,有2個Pod處於Running狀態,其他3個仍處於Pending狀態。

    此時,叢集所有的彈性配額都使用其min設定的保障資源(Guaranteed Resource)。

相關文檔

  • kube-scheduler發布記錄,請參見kube-scheduler

  • ACK基於新版的Kube-scheduler架構實現Gang scheduling的能力。Gang scheduling主要用於確保一組關聯的Pod能夠同時調度到叢集中的節點上,或者如果無法滿足這種條件,則這些Pod都不會被調度,解決原生調度器無法支援All-or-Nothing作業調度的問題。這種策略在執行需要嚴格同步或共用資源的分布式應用時非常有用,例如Spark、Hadoop等巨量資料處理任務。詳細資料,請參見使用Gang scheduling