在 GKE 上實作工作佇列系統,並在命名空間之間共用配額

本教學課程使用 Kueue,說明如何實作工作佇列系統、在 Google Kubernetes Engine (GKE) 上設定不同命名空間之間的工作負載資源和配額共用,以及盡量提高叢集使用率。

背景

身為基礎架構工程師或叢集管理員,盡量提高命名空間之間的資源用量非常重要。一個命名空間中的工作批次可能無法完全使用指派給該命名空間的完整配額,而另一個命名空間可能有多個待處理的工作。如要在不同命名空間的工作之間有效運用叢集資源,並提高配額管理彈性,可以在 Kueue 中設定同類群組。同類群組是一組 ClusterQueue,可互相借用未使用的配額。 ClusterQueue 會控管 CPU、記憶體和硬體加速器等資源集區。

如要進一步瞭解這些概念,請參閱 Kueue 說明文件

建立 ResourceFlavors

ResourceFlavor 代表叢集節點中的資源變體,例如不同的 VM (例如 Spot 與隨選)、架構 (例如 x86 與 ARM CPU)、品牌和型號 (例如 Nvidia A100 與 T4 GPU)。

ResourceFlavor 會使用節點標籤和汙點,與叢集中的一組節點相符。

apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: on-demand # This ResourceFlavor will be used for the CPU resource
spec:
  nodeLabels:
    cloud.google.com/gke-provisioning: standard # This label was applied automatically by GKE
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: spot # This ResourceFlavor will be used as added resource for the CPU resource
spec:
  nodeLabels:  
    cloud.google.com/gke-provisioning: spot # This label was applied automatically by GKE

在這個資訊清單中:

  • ResourceFlavor on-demand 的標籤已設為 cloud.google.com/gke-provisioning: standard
  • ResourceFlavor spot 的標籤已設為 cloud.google.com/gke-provisioning: spot

工作負載獲派 ResourceFlavor 時,Kueue 會將工作負載的 Pod 指派給符合 ResourceFlavor 所定義節點標籤的節點。

部署 ResourceFlavor:

kubectl apply -f flavors.yaml

建立 ClusterQueue 和 LocalQueue

建立兩個 ClusterQueue cq-team-acq-team-b,以及對應的 LocalQueue lq-team-alq-team-b,分別命名空間為 team-ateam-b

ClusterQueue 是叢集範圍的物件,可控管 CPU、記憶體和硬體加速器等資源集區。批次管理員可以限制批次使用者查看這些物件。

LocalQueue 是命名空間物件,批次使用者可以列出這些物件。這些指標會指向 ClusterQueues,資源會從中分配,以執行 LocalQueue 工作負載。

apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: cq-team-a
spec:
  cohort: all-teams # cq-team-a and cq-team-b share the same cohort
  namespaceSelector:
    matchLabels:
      kubernetes.io/metadata.name: team-a #Only team-a can submit jobs direclty to this queue, but will be able to share it through the cohort
  resourceGroups:
  - coveredResources: ["cpu", "memory"]
    flavors:
    - name: on-demand
      resources:
      - name: "cpu"
        nominalQuota: 10
        borrowingLimit: 5
      - name: "memory"
        nominalQuota: 10Gi
        borrowingLimit: 15Gi
    - name: spot # This ClusterQueue doesn't have nominalQuota for spot, but it can borrow from others
      resources:
      - name: "cpu"
        nominalQuota: 0
      - name: "memory"
        nominalQuota: 0
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: team-a # LocalQueue under team-a namespace
  name: lq-team-a
spec:
  clusterQueue: cq-team-a # Point to the ClusterQueue team-a-cq

ClusterQueues 允許資源有多種風味。在本例中,兩個 ClusterQueue 都有兩種變種版本,分別是 on-demandspot,各自提供 cpu 資源。ResourceFlavor spot 的配額設為 0,目前不會使用。

兩個 ClusterQueue 共用同一個群組 (稱為 all-teams),定義於 .spec.cohort 中。 如果兩個以上的 ClusterQueue 共用同一個群組,彼此就能借用未使用的配額。

如要進一步瞭解同類群組的運作方式和借用語意,請參閱 Kueue 說明文件

部署 ClusterQueue 和 LocalQueue:

kubectl apply -f cq-team-a.yaml
kubectl apply -f cq-team-b.yaml

(選用) 使用 kube-prometheus 監控工作負載

您可以使用 Prometheus 監控有效和待處理的 Kueue 工作負載。如要監控啟動的工作負載,並觀察每個 ClusterQueue 的負載,請將 kube-prometheus 部署至命名空間 monitoring 下的叢集:

  1. 下載 Prometheus 運算子的原始碼:

    cd
    git clone https://github.com/prometheus-operator/kube-prometheus.git
    
  2. 建立 CustomResourceDefinitions(CRD):

    kubectl create -f kube-prometheus/manifests/setup
    
  3. 建立監控元件:

    kubectl create -f kube-prometheus/manifests
    
  4. 允許 prometheus-operator 從 Kueue 元件擷取指標:

    kubectl apply -f https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/prometheus.yaml
    
  5. 變更為工作目錄:

    cd kubernetes-engine-samples/batch/kueue-cohort
    
  6. 將通訊埠轉送設定為在 GKE 叢集中執行的 Prometheus 服務:

    kubectl --namespace monitoring port-forward svc/prometheus-k8s 9090
    
  7. 在瀏覽器中開啟 localhost:9090 的 Prometheus 網頁 UI。

    在 Cloud Shell 中:

    1. 按一下「網頁預覽」

    2. 按一下「變更通訊埠」,然後將通訊埠編號設為 9090

    3. 按一下「變更並預覽」

    系統會顯示下列 Prometheus 網頁版 UI。

    Prometheus 網頁 UI 的螢幕截圖

  8. 在「Expression」(運算式) 查詢方塊中輸入下列查詢,建立第一個面板,監控 cq-team-a ClusterQueue 的現行工作負載:

    kueue_pending_workloads{cluster_queue="cq-team-a", status="active"} or kueue_admitted_active_workloads{cluster_queue="cq-team-a"}
    
  9. 按一下「新增面板」

  10. 在「Expression」(運算式) 查詢方塊中輸入下列查詢,建立另一個面板來監控 cq-team-b ClusterQueue 的現行工作負載:

    kueue_pending_workloads{cluster_queue="cq-team-b", status="active"} or kueue_admitted_active_workloads{cluster_queue="cq-team-b"}
    
  11. 按一下「新增面板」

  12. 在「Expression」(運算式) 查詢方塊中輸入下列查詢,建立監控叢集節點數量的面板:

    count(kube_node_info)
    

(選用) 使用 Google Cloud Managed Service for Prometheus 監控工作負載

您可以使用 Google Cloud Managed Service for Prometheus 監控作用中和待處理的 Kueue 工作負載。如需完整的指標清單,請參閱 Kueue 說明文件

  1. 設定身分和 RBAC,以存取指標:

    下列設定會建立 4 個 Kubernetes 資源,為 Google Cloud Managed Service for Prometheus 收集器提供指標存取權。

    • 存取 Kueue 指標時,系統會使用 kueue-system 命名空間中的 kueue-metrics-reader ServiceAccount 進行驗證。

    • kueue-metrics-reader 服務帳戶相關聯的 Secret 會儲存驗證權杖,供收集器用來向 Kueue 部署作業公開的指標端點進行驗證。

    • kueue-system 命名空間中名為 kueue-secret-reader 的角色,可讀取含有服務帳戶權杖的密鑰。

    • 授予 kueue-metrics-reader 服務帳戶 kueue-metrics-reader ClusterRole 的 ClusterRoleBinding。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
     name: kueue-metrics-reader
     namespace: kueue-system
    ---
    apiVersion: v1
    kind: Secret
    metadata:
     name: kueue-metrics-reader-token
     namespace: kueue-system
     annotations:
       kubernetes.io/service-account.name: kueue-metrics-reader
    type: kubernetes.io/service-account-token
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
     name: kueue-secret-reader
     namespace: kueue-system
    rules:
    -   resources:
     -   secrets
     apiGroups: [""]
     verbs: ["get", "list", "watch"]
     resourceNames: ["kueue-metrics-reader-token"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
     name: kueue-metrics-reader
    subjects:
    -   kind: ServiceAccount
     name: kueue-metrics-reader
     namespace: kueue-system
    roleRef:
     kind: ClusterRole
     name: kueue-metrics-reader
     apiGroup: rbac.authorization.k8s.io
    
  2. 為 Google Cloud Managed Service for Prometheus 設定 RoleBinding:

    視您使用的是 Autopilot 或 Standard 叢集而定,您需要在 gke-gmp-systemgmp-system 命名空間中建立 RoleBinding。這個資源可讓收集器服務帳戶存取 kueue-metrics-reader-token 密鑰,以驗證及擷取 Kueue 指標。

    Autopilot

      apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        name: gmp-system:collector:kueue-secret-reader
        namespace: kueue-system
      roleRef:
        name: kueue-secret-reader
        kind: Role
        apiGroup: rbac.authorization.k8s.io
      subjects:
      -   name: collector
        namespace: gke-gmp-system
        kind: ServiceAccount
    

    標準

      apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        name: gmp-system:collector:kueue-secret-reader
        namespace: kueue-system
      roleRef:
        name: kueue-secret-reader
        kind: Role
        apiGroup: rbac.authorization.k8s.io
      subjects:
      -   name: collector
        namespace: gmp-system
        kind: ServiceAccount
    
  3. 設定 PodMonitoring 資源:

    下列資源會設定 Kueue 部署作業的監控功能,並指定透過 HTTPS 在 /metrics 路徑公開指標。在擷取指標時,系統會使用 kueue-metrics-reader-token 密鑰進行驗證。

    apiVersion: monitoring.googleapis.com/v1
    kind: PodMonitoring
    metadata:
    name: kueue
    namespace: kueue-system
    spec:
    selector:
     matchLabels:
       control-plane: controller-manager
    endpoints:
    -   port: 8443
     interval: 30s
     path: /metrics
     scheme: https
     tls:
       insecureSkipVerify: true
     authorization:
       type: Bearer
       credentials:
         secret:
           name: kueue-metrics-reader-token
           key: token
    

查詢匯出的指標

監控以 Kueue 為基礎的系統時,可使用的 PromQL 查詢範例

您可以透過這些 PromQL 查詢監控重要的 Kueue 指標,例如工作輸送量、佇列的資源使用率和工作負載等待時間,瞭解系統效能並找出潛在瓶頸。

工作處理量

這會計算每個 cluster_queue 在 5 分鐘內允許的工作負載每秒速率。這項指標有助於按佇列細分,找出瓶頸,加總後則可得出整體系統輸送量。

查詢:

sum(rate(kueue_admitted_workloads_total[5m])) by (cluster_queue)

資源使用率

前提是 metrics.enableClusterQueueResources 已啟用。系統會計算每個佇列的目前 CPU 使用量與名義 CPU 配額比率。值越接近 1,表示用量越高。您可以變更資源標籤,將此範例用於記憶體或其他資源。

如要在叢集中安裝自訂設定的 Kueue 發布版本,請參閱 Kueue 說明文件

查詢:

sum(kueue_cluster_queue_resource_usage{resource="cpu"}) by (cluster_queue) / sum(kueue_cluster_queue_nominal_quota{resource="cpu"}) by (cluster_queue)

佇列等待時間

這項指標會顯示特定佇列中工作負載的第 90 百分位等待時間。您可以修改分位數值 (例如中位數為 0.5,第 99 個百分位數為 0.99),瞭解等待時間分布情形。

查詢:

histogram_quantile(0.9, kueue_admission_wait_time_seconds_bucket{cluster_queue="QUEUE_NAME"})

建立工作並觀察允許的工作負載

在本節中,您將在 team-ateam-b 命名空間下建立 Kubernetes Job。Kubernetes 中的 Job 控制器會建立一或多個 Pod,並確保這些 Pod 成功執行特定工作。

產生要傳送至兩個 ClusterQueue 的工作,這些工作會休眠 10 秒,並以三個平行工作完成。然後在 60 秒後清除。

apiVersion: batch/v1
kind: Job
metadata:
  namespace: team-a # Job under team-a namespace
  generateName: sample-job-team-a-
  labels:
    kueue.x-k8s.io/queue-name: lq-team-a # Point to the LocalQueue
spec:
  ttlSecondsAfterFinished: 60 # Job will be deleted after 60 seconds
  parallelism: 3 # This Job will have 3 replicas running at the same time
  completions: 3 # This Job requires 3 completions
  suspend: true # Set to true to allow Kueue to control the Job when it starts
  template:
    spec:
      containers:
      - name: dummy-job
        image: gcr.io/k8s-staging-perf-tests/sleep:latest
        args: ["10s"] # Sleep for 10 seconds
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
      restartPolicy: Never

job-team-a.yaml 會在 team-a 命名空間下建立 Job,並指向 LocalQueue lq-team-a 和 ClusterQueue cq-team-a

同樣地,job-team-b.yaml 會在 team-b 命名空間下建立 Job,並指向 LocalQueue lq-team-b 和 ClusterQueue cq-team-b

  1. 啟動新的終端機,然後執行這個指令碼,每秒產生一個 Job:

    ./create_jobs.sh job-team-a.yaml 1
    
  2. 啟動另一個終端機,並為 team-b 命名空間建立 Job:

    ./create_jobs.sh job-team-b.yaml 1
    
  3. 觀察 Prometheus 中排入佇列的工作。或使用下列指令:

    watch -n 2 kubectl get clusterqueues -o wide
    

畫面會顯示如下的輸出內容:

    NAME        COHORT      STRATEGY         PENDING WORKLOADS   ADMITTED WORKLOADS
    cq-team-a   all-teams   BestEffortFIFO   0                   5
    cq-team-b   all-teams   BestEffortFIFO   0                   4

透過同類群組借用未使用的配額

ClusterQueues 可能無法隨時達到最大容量。如果工作負載未平均分配到 ClusterQueues,配額用量就不會達到上限。如果 ClusterQueue 之間共用相同同類群組,ClusterQueue 可以從其他 ClusterQueue 借用配額,盡量提高配額使用率。

  1. 當 ClusterQueues cq-team-acq-team-b 都有排隊等待的作業時,請在對應的終端機上按下 CTRL+c,停止 team-b 命名空間的指令碼。

  2. 處理完命名空間 team-b 的所有待處理工作後,命名空間 team-a 的工作即可借用 cq-team-b 中的可用資源:

    kubectl describe clusterqueue cq-team-a
    

    由於 cq-team-acq-team-b 共用名為 all-teams 的相同同類群組,因此這些 ClusterQueue 能夠共用未使用的資源。

      Flavors Usage:
        Name:  on-demand
        Resources:
          Borrowed:  5
          Name:      cpu
          Total:     15
          Borrowed:  5Gi
          Name:      memory
          Total:     15Gi
    
  3. 繼續執行 team-b 命名空間的指令碼。

    ./create_jobs.sh job-team-b.yaml 3
    

    觀察從 cq-team-a 借用的資源如何返回 0,而 cq-team-b 的資源則用於自身的工作負載:

    kubectl describe clusterqueue cq-team-a
    
      Flavors Usage:
        Name:  on-demand
        Resources:
          Borrowed:  0
          Name:      cpu
          Total:     9
          Borrowed:  0
          Name:      memory
          Total:     9Gi
    

使用 Spot VM 增加配額

如果需要暫時增加配額 (例如滿足待處理工作負載的高需求),您可以將更多 ClusterQueue 新增至同類群組,藉此設定 Kueue 來滿足需求。如果 ClusterQueue 有未使用的資源,可以與同類群組的其他 ClusterQueue 共用這些資源。

在本教學課程的開頭,您使用 Spot VM 建立名為 spot 的節點集區,並建立名為 spot 的 ResourceFlavor,標籤設為 cloud.google.com/gke-provisioning: spot。建立 ClusterQueue,以使用這個節點集區和代表該節點集區的 ResourceFlavor:

  1. 建立名為 cq-spot 的新 ClusterQueue,並將同類群組設為 all-teams

    apiVersion: kueue.x-k8s.io/v1beta1
    kind: ClusterQueue
    metadata:
      name: spot-cq
    spec:
      cohort: all-teams # Same cohort as cq-team-a and cq-team-b
      resourceGroups:
      - coveredResources: ["cpu", "memory"]
        flavors:
        - name: spot
          resources:
          - name: "cpu"
            nominalQuota: 40
          - name: "memory"
            nominalQuota: 144Gi

    由於這個 ClusterQueue 與 cq-team-acq-team-b 共用相同群組,因此 ClusterQueue cq-team-acq-team-b 最多可借用 15 個 CPU 要求和 15 Gi 的記憶體。

    kubectl apply -f cq-spot.yaml
    
  2. 在 Prometheus 中,觀察由於 cq-spot 新增配額,cq-team-acq-team-b 允許的工作負載如何大幅增加,因為 cq-spot 與兩者共用相同群組。或使用下列指令:

    watch -n 2 kubectl get clusterqueues -o wide
    
  3. 在 Prometheus 中,觀察叢集中的節點數量。或使用下列指令:

    watch -n 2 kubectl get nodes -o wide
    
  4. 針對 team-ateam-b 命名空間按下 CTRL+c,停止兩個指令碼。