使用 KEDA 將資源縮減為零

本教學課程說明如何使用 KEDA,將 GKE 工作負載縮減至零個 Pod。將部署項目縮減為零個 Pod,可在閒置期間 (例如週末和非上班時間) 節省資源,或用於間歇性工作負載 (例如週期性工作)。

目標

本教學課程將說明下列用途:

費用

在本文件中,您會使用下列 Google Cloud的計費元件:

您可以使用 Pricing Calculator,根據預測用量估算費用。

初次使用 Google Cloud 的使用者可能符合免費試用期資格。

完成本文所述工作後,您可以刪除建立的資源,避免繼續計費,詳情請參閱「清除所用資源」。

事前準備

在本教學課程中,您將使用 Cloud Shell 執行指令。Cloud Shell 是殼層環境,用於管理託管在 Google Cloud的資源。這個環境已預先安裝 Google Cloud CLIkubectlHelmTerraform 指令列工具。如果您未使用 Cloud Shell,則必須安裝 Google Cloud CLI 和 Helm。

  1. 如要在本頁面執行指令,請在下列其中一種開發環境中設定 gcloud CLI:

    Cloud Shell

    如要使用已設定 gcloud CLI 的線上終端機,請啟用 Cloud Shell:

    頁面底部會開啟 Cloud Shell 工作階段,並顯示指令列提示。工作階段可能要幾秒鐘的時間才能初始化。

    本機殼層

    如要使用本機開發環境,請按照下列步驟操作:

    1. 安裝 gcloud CLI。
    2. 初始化 gcloud CLI。
    3. 安裝 Kubernetes 套件管理工具 Helm。
  2. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  3. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  4. Verify that billing is enabled for your Google Cloud project.

  5. Enable the Resource Manager, Compute Engine, GKE, Pub/Sub APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  6. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  7. Verify that billing is enabled for your Google Cloud project.

  8. Enable the Resource Manager, Compute Engine, GKE, Pub/Sub APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  9. 正在設定環境

    如要使用 Cloud Shell 設定環境,請按照下列步驟操作:

    1. 設定環境變數:

      export PROJECT_ID=PROJECT_ID
      export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format 'get(projectNumber)')
      export LOCATION=LOCATION
      

      請將 PROJECT_ID 替換為您的 Google Cloud 專案 ID,並將 LOCATION 替換為要建立 GKE 叢集的區域或可用區

      如果您未在單一工作階段中完成整個教學課程,或環境變數因故未設定,請務必再次執行這項指令,重新設定變數。

    2. 建立啟用叢集自動調度GKE 適用的工作負載身分聯盟的 Standard GKE 叢集:

      gcloud container clusters create scale-to-zero \
          --project=${PROJECT_ID} --location=${LOCATION} \
          --machine-type=n1-standard-2 \
          --enable-autoscaling --min-nodes=1 --max-nodes=5 \
          --workload-pool=${PROJECT_ID}.svc.id.goog
      

    安裝 KEDA

    KEDA 是 Kubernetes 水平 Pod 自動配置器的輔助元件。使用 KEDA,您可以將 Deployment 調度至零個 Pod,也可以從零個 Pod 調度至一個 Pod。Deployment 是 Kubernetes API 物件,可讓您執行多個 Pod 副本,並將這些副本分散到叢集中的節點。GKE 建立至少一個 Pod 後,就會套用標準的水平 Pod 自動配置器演算法

    GKE 將 Deployment 縮減為零個 Pod 後,由於沒有任何 Pod 正在執行,自動調度功能無法依據 CPU 使用率等 Pod 指標運作。因此,KEDA 允許使用 Kubernetes External Metrics API 的實作項目,擷取叢集外部的指標。您可以根據指標 (例如 Pub/Sub 訂閱中未處理的訊息數) 使用這項 API 自動調度資源。如需所有支援的指標來源清單,請參閱 KEDA 說明文件

    使用 Helm 或 kubectl 在叢集上安裝 KEDA。

    Helm

    執行下列指令,新增 KEDA Helm 存放區、安裝 KEDA Helm 資訊套件,並授予 KEDA 服務帳戶 Cloud Monitoring 的讀取權:

    helm repo add kedacore https://kedacore.github.io/charts
    helm repo update
    helm install keda kedacore/keda --create-namespace --namespace keda
    
    gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
         --role roles/monitoring.viewer \
         --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda/sa/keda-operator
    

    請注意,這項指令也會設定授權規則,要求叢集必須設定 Workload Identity Federation for GKE。

    kubectl

    執行下列指令,使用 kubectl apply 安裝 KEDA,並授予 KEDA 服務帳戶 Cloud Monitoring 的讀取權:

    kubectl apply --server-side  -f https://github.com/kedacore/keda/releases/download/v2.15.1/keda-2.15.1.yaml
    
    gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
         --role roles/monitoring.viewer \
         --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda/sa/keda-operator
    

    請注意,這項指令也會設定授權規則,要求叢集必須設定 Workload Identity Federation for GKE。

    確認所有 KEDA 資源都顯示在 keda 命名空間下:

    kubectl get all -n keda
    

    如要進一步瞭解 KEDA 設計和資源,請參閱 KEDA 說明文件

    將 Pub/Sub 工作負載的資源調度降到零

    本節說明如何處理 Pub/Sub 訂閱項目的訊息、處理每則訊息,以及確認訊息處理完成的工作負載。工作負載會動態調度資源:隨著未確認訊息數量增加,自動調度資源會例項化更多 Pod,確保及時處理訊息。

    如果一段時間內未收到任何訊息,將 Pod 數量調為零可確保系統不會例項化任何 Pod。這樣可節省資源,因為不會有 Pod 長時間閒置。

    部署 Pub/Sub 工作負載

    部署範例工作負載,處理 Pub/Sub 主題中排入佇列的訊息。為模擬實際工作負載,這個範例程式會在確認訊息前等待三秒。工作負載已設定為在 keda-pubsub-sa 服務帳戶下執行。

    執行下列指令,在 keda-pubsub 命名空間下建立 Pub/Sub 主題和訂閱項目、設定權限,並建立啟動工作負載的部署。

    gcloud pubsub topics create keda-echo
    gcloud pubsub subscriptions create keda-echo-read --topic=keda-echo
    gcloud projects add-iam-policy-binding projects/${PROJECT_ID}  \
        --role=roles/pubsub.subscriber \
      --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda-pubsub/sa/keda-pubsub-sa
    
    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/cloud-pubsub/deployment/keda-pubsub-with-workload-identity.yaml
    

    設定將資源調度率降至零

    如要將 Pub/Sub 工作負載設定為縮減至零,請使用 KEDA 定義 ScaledObject 資源,指定部署作業的縮放方式。接著,KEDA 會自動建立及管理基礎 HorizontalPodAutoscaler (HPA) 物件。

    1. 建立 ScaledObject 資源,說明預期的自動調度資源行為:

      curl https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/cloud-pubsub/deployment/keda-pubsub-scaledobject.yaml | envsubst | kubectl apply -f -
      

      這會建立下列物件:

      apiVersion: keda.sh/v1alpha1
      kind: ScaledObject
      metadata:
        name: keda-pubsub
        namespace: keda-pubsub
      spec:
        maxReplicaCount: 5
        scaleTargetRef:
          name: keda-pubsub
        triggers:
          - type: gcp-pubsub
            authenticationRef:
              name: keda-auth
            metadata:
              subscriptionName: "projects/${PROJECT_ID}/subscriptions/keda-echo-read"
      
    2. 檢查 KEDA 根據 ScaledObject 物件建立的 HorizontalPodAutoscaler (HPA) 物件:

      kubectl get hpa keda-hpa-keda-pubsub -n keda-pubsub -o yaml
      

      如要進一步瞭解自動調度,請參閱 Kubernetes 說明文件

    3. 等待 KEDA 確認 Pub/Sub 訂閱項目為空,並將 Deployment 擴展至零個副本。

      檢查工作負載自動調度器:

      kubectl describe hpa keda-hpa-keda-pubsub -n keda-pubsub
      

      請注意,在指令回應中,ScalingActive 條件為 false。 相關訊息顯示,水平 Pod 自動調度器確認 KEDA 已將 Deployment 縮減為零,此時會停止運作,直到 Deployment 重新擴增為一個 Pod 為止。

      Name:                                                  keda-hpa-keda-pubsub
      Namespace:                                             keda-pubsub
      Metrics:                                               ( current / target )
        "s0-gcp-ps-projects-[...]]" (target average value):  0 / 10
      Min replicas:                                          1
      Max replicas:                                          5
      Deployment pods:                                       5 current / 5 desired
      Conditions:
        Type            Status  Reason               Message
        ----            ------  ------               -------
        AbleToScale     True    ScaleDownStabilized  recent recommendations were higher than current one [...]
        ScalingActive   False   ScalingDisabled      scaling is disabled since the replica count of the target is zero
        ScalingLimited  True    TooManyReplicas      the desired replica count is more than the maximum replica count
      

    觸發擴大作業

    如要刺激 Deployment 擴大規模,請執行下列步驟:

    1. 將訊息加入 Pub/Sub 主題的佇列:

      for num in {1..20}
      do
        gcloud pubsub topics publish keda-echo --project=${PROJECT_ID} --message="Test"
      done
      
    2. 確認 Deployment 正在擴充:

      kubectl get deployments -n keda-pubsub
      

      在輸出中,觀察「Ready」欄是否顯示一個副本:

      NAME          READY   UP-TO-DATE   AVAILABLE   AGE
      keda-pubsub   1/1     1            1           2d
      

    KEDA 觀察到佇列不為空後,會擴大 Deployment。

    將 LLM 工作負載的資源調度降到零

    本節說明如何部署大型語言模型 (LLM) 工作負載,並附加 GPU 來部署 Ollama 伺服器。Ollama 可執行熱門的 LLM,例如 GemmaLlama 2,並主要透過 HTTP 公開其功能。

    安裝 KEDA-HTTP 外掛程式

    在閒置期間將 HTTP 服務縮減至零個 Pod,會導致要求失敗,因為沒有後端可處理要求。

    本節說明如何使用 KEDA-HTTP 外掛程式解決這個問題。KEDA-HTTP 會啟動 HTTP Proxy,接收使用者要求並轉送至設定為縮減至零的服務。如果 Service 沒有 Pod,Proxy 會觸發 Service 擴大,並緩衝處理要求,直到 Service 擴大至至少一個 Pod 為止。

    使用 Helm 安裝 KEDA-HTTP 外掛程式。詳情請參閱 KEDA-HTTP 說明文件

    helm repo add ollama-helm https://otwld.github.io/ollama-helm/
    helm repo update
    
    # Set the proxy timeout to 120s, giving Ollama time to start.
    helm install http-add-on kedacore/keda-add-ons-http  \
      --create-namespace --namespace keda \
      --set interceptor.responseHeaderTimeout=120s
    

    部署 Ollama LLM 工作負載

    如要部署 Ollama LLM 工作負載,請按照下列步驟操作:

    1. 建立包含 g2-standard-4 個節點的節點集區,並附加 GPU,然後將叢集自動調度資源功能設為提供零到兩個節點:

      gcloud container node-pools create gpu --machine-type=g2-standard-4 \
          --location=${LOCATION} --cluster=scale-to-zero \
          --min-nodes 0 --max-nodes 2 --num-nodes=1 --enable-autoscaling
      
    2. 新增官方 Ollama Helm 資訊套件存放區,並更新本機 Helm 用戶端的存放區:

      helm repo add ollama-helm https://otwld.github.io/ollama-helm/
      helm repo update
      
    3. 使用 Helm 資訊套件部署 Ollama 伺服器:

      helm install ollama ollama-helm/ollama --create-namespace --namespace ollama \
        -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/ollama/helm-values-ollama.yaml
      

      helm-values-ollama.yaml 設定會指定要載入的 LLM 模型、GPU 需求,以及 Ollama 伺服器的 TCP 連接埠。

    設定將資源調度率降至零

    如要將 Ollama 工作負載設定為縮減至零,KEDA-HTTP 會使用 HTTPScaledObject

    1. 建立 HTTPScaledObject 資源,說明預期的自動調度資源行為:

      kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/ollama/keda-ollama-httpscaledobject.yaml
      

      這會建立 HTTPScaledObject 物件,定義下列欄位:

      • scaleTargetRef:指定 KEDA-HTTP 應將要求轉送至的服務。在本範例中,所有含有主機 ollama.ollama 的要求都會轉送至 Ollama 伺服器。
      • scaledownPeriod:指定在未收到任何要求時,縮減規模的速度 (以秒為單位)。
      • replicas:指定 Ollama 部署作業要維護的 Pod 數量下限和上限。
      • scalingMetric:指定用於自動調度資源的指標,例如本例中的要求率。如需更多指標選項,請參閱 KEDA-HTTP 說明文件
      kind: HTTPScaledObject
      apiVersion: http.keda.sh/v1alpha1
      metadata:
          namespace: ollama
          name: ollama
      spec:
          hosts:
          - ollama.ollama
          scaleTargetRef:
              name: ollama
              kind: Deployment
              apiVersion: apps/v1
              service: ollama
              port: 11434
          replicas:
              min: 0
              max: 2
          scaledownPeriod: 3600
          scalingMetric:
              requestRate:
                  targetValue: 20
      
    2. 執行下列指令,確認 KEDA-HTTP 已順利處理上一個步驟中建立的 HTTPScaledObject

      kubectl get hpa,scaledobject -n ollama
      

      輸出內容會顯示 HorizontalPodAutoscaler (由 KEDA 建立) 和 ScaledObject (由 KEDA-HTTP 建立) 資源:

      NAME                                                  REFERENCE           TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
      horizontalpodautoscaler.autoscaling/keda-hpa-ollama   Deployment/ollama   0/100 (avg)   1         2         1          2d
      
      NAME                          SCALETARGETKIND      SCALETARGETNAME   MIN   MAX   TRIGGERS        AUTHENTICATION   READY   ACTIVE   FALLBACK   PAUSED    AGE
      scaledobject.keda.sh/ollama   apps/v1.Deployment   ollama            0     2     external-push                    True    False    False      Unknown   2d
      
    3. 確認 Deployment 會將 Pod 數量縮減至零。

      等待 scaledownPeriod 欄位中設定的時間長度,然後執行指令:

      kubectl get deployments -n ollama
      

      輸出結果顯示 KEDA 已縮減 Ollama 部署作業,且沒有任何 Pod 正在執行:

      NAME     READY   UP-TO-DATE   AVAILABLE   AGE
      ollama   0/0     0            0           2d
      

    觸發擴大作業

    如要刺激 Deployment 擴充,請使用 KEDA-HTTP 外掛程式設定的 Proxy 呼叫 Ollama 服務。這會導致要求率指標值增加,並觸發第一個 Pod 的建立作業。

    由於 Proxy 不會向外公開,因此請使用 kubectl 通訊埠轉送功能存取 Proxy。

    kubectl port-forward svc/keda-add-ons-http-interceptor-proxy -n keda 8080:8080 &
    
    # Set the 'Host' HTTP header so that the proxy routes requests to the Ollama server.
    curl -H "Host: ollama.ollama" \
      http://localhost:8080/api/generate \
      -d '{ "model": "gemma:7b", "prompt": "Hello!" }'
    

    curl 指令會將「Hello!」提示傳送至 Gemma 模型。觀察回覆中傳回的答案權杖。如需 API 規格,請參閱 Ollama 指南

    清除所用資源

    為避免因為本教學課程所用資源,導致系統向 Google Cloud 收取費用,請刪除含有相關資源的專案,或者保留專案但刪除個別資源。

    1. 清除 Pub/Sub 訂閱與主題:

      gcloud pubsub subscriptions delete keda-echo-read
      gcloud pubsub topics delete keda-echo
      
    2. 刪除您的 GKE 叢集:

      gcloud container clusters delete scale-to-zero --location=${LOCATION}
      

    後續步驟