使用 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.

    Go to project selector

  4. Make sure that billing is enabled for your Google Cloud project.

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

    Enable the APIs

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

    Go to project selector

  7. Make sure that billing is enabled for your Google Cloud project.

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

    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 的實作項目,擷取來自叢集外部的指標。您可以使用這項 API,根據指標 (例如 Pub/Sub 訂閱中未處理的訊息數) 自動調度資源。如需所有支援的指標來源清單,請參閱 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 長時間處於閒置狀態。

部署 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,例如 GemmaLamma 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}
    

後續步驟