設定彈性跨區域高可用性

本文說明如何使用 Google Kubernetes Engine (GKE) 多叢集推論閘道和 GKE 自動調整功能,為 AI 推論工作負載設定彈性跨區域高可用性。透過這項設定,您可以在不同地區的多個 GKE 叢集之間,智慧地進行工作負載的負載平衡。

如要進一步瞭解 GKE 多叢集推論閘道,請參閱「關於 GKE 多叢集推論閘道」。

事前準備

  1. 啟用 Google Kubernetes Engine API。

    啟用 Google Kubernetes Engine API

  2. 如果您打算使用 Google Cloud CLI 執行這項工作,請安裝並初始化該工具。

  3. 請確認專案有足夠的 H100 GPU 配額。詳情請參閱「GPU 配額」和「資源分配」。

  4. 使用 GKE 1.34.1-gke.1127000 以上版本。

  5. 使用 gcloud CLI 480.0.0 以上版本。

  6. 請確認節點使用的服務帳戶具備 roles/monitoring.metricWriterroles/stackdriver.resourceMetadata.writer 權限。

  7. 確認您在專案中具備 roles/container.adminroles/iam.serviceAccountAdmin Identity and Access Management (IAM) 角色。

  8. 完成下列 Hugging Face 必要條件:

    1. 建立 Hugging Face 帳戶。
    2. 在 Hugging Face 上要求並取得 Llama 3.1 模型存取權。
    3. 在 Hugging Face 的模型頁面上簽署授權同意聲明協議。
    4. 生成至少具備讀取權限的 Hugging Face 存取權杖。

建立叢集和節點集區

如要在不同區域建立兩個 GKE 叢集,並設定節點集區,請按照下列步驟操作:

  1. 建立第一個叢集:

    gcloud container clusters create gke-west --zone \
        CLUSTER_1_ZONE \
        --project=PROJECT_ID \
        --gateway-api=standard \
        --cluster-version=GKE_VERSION \
        --machine-type="MACHINE_TYPE" \
        --disk-type="DISK_TYPE" \
        --enable-managed-prometheus --monitoring=SYSTEM,DCGM \
        --hpa-profile=performance \
        --workload-pool=PROJECT_ID.s3ns.svc.id.goog \
        --async
    

    更改下列內容:

    • PROJECT_ID:專案 ID
    • CLUSTER_1_ZONE:第一個叢集的區域,例如 europe-west3-c
    • GKE_VERSION:要使用的 GKE 版本,例如 1.34.1-gke.1127000
    • MACHINE_TYPE:叢集節點的機型,例如 c2-standard-16
    • DISK_TYPE:叢集節點的磁碟類型,例如 pd-standard
  2. 在第一個叢集中建立 H100 節點集區:

    gcloud container node-pools create h100 \
        --accelerator "type=nvidia-h100-80gb,count=2,gpu-driver-version=latest" \
        --project=PROJECT_ID \
        --location=CLUSTER_1_ZONE \
        --node-locations=CLUSTER_1_ZONE \
        --cluster=CLUSTER_1_NAME \
        --machine-type=NODE_POOL_MACHINE_TYPE \
        --num-nodes=NUM_NODES \
        --spot \
        --min-nodes=MIN_NUM_NODES \
        --max-nodes=MAX_NUM_NODES \
        --enable-autoscaling \
        --async
    

    更改下列內容:

    • PROJECT_ID:專案 ID
    • CLUSTER_1_ZONE:第一個叢集的區域,例如 europe-west3-c
    • CLUSTER_1_NAME:第一個叢集的名稱,例如 gke-west
    • NODE_POOL_MACHINE_TYPE:節點集區的機型,例如 a3-highgpu-2g
    • NUM_NODES:節點集區中的節點數量,例如 3
    • MIN_NUM_NODES:節點集區中自動調度資源的節點數量下限,例如 1
    • MAX_NUM_NODES:節點集區中自動調度資源的節點數量上限,例如 10
  3. 取得憑證,並在第一個叢集中建立 Hugging Face 權杖密鑰:

    gcloud container clusters get-credentials CLUSTER_1_NAME \
        --location CLUSTER_1_ZONE \
        --project=PROJECT_ID
    
    kubectl create secret generic hf-token \
        --from-literal=token=HF_TOKEN
    

    更改下列內容:

    • PROJECT_ID:專案 ID
    • CLUSTER_1_NAME:第一個叢集的名稱,例如 gke-west
    • CLUSTER_1_ZONE:第一個叢集的區域,例如 europe-west3-c
    • HF_TOKEN:您的 Hugging Face 存取權杖
  4. 在與第一個叢集不同的區域中建立第二個叢集:

    gcloud container clusters create gke-east --zone CLUSTER_2_ZONE \
        --project=PROJECT_ID \
        --gateway-api=standard \
        --cluster-version=GKE_VERSION \
        --machine-type="MACHINE_TYPE" \
        --disk-type="DISK_TYPE" \
        --enable-managed-prometheus \
        --monitoring=SYSTEM,DCGM \
        --hpa-profile=performance \
        --workload-pool=PROJECT_ID.s3ns.svc.id.goog \
        --async
    

    CLUSTER_2_ZONE 替換為第二個叢集的區域,例如 us-east4-a

  5. 為第二個叢集建立 H100 節點集區:

    gcloud container node-pools create h100 \
        --accelerator "type=nvidia-h100-80gb,count=2,gpu-driver-version=latest" \
        --project=PROJECT_ID \
        --location=CLUSTER_2_ZONE \
        --node-locations=CLUSTER_2_ZONE \
        --cluster=CLUSTER_2_NAME \
        --machine-type=NODE_POOL_MACHINE_TYPE \
        --num-nodes=NUM_NODES \
        --spot \
        --min-nodes=MIN_NUM_NODES \
        --max-nodes=MAX_NUM_NODES \
        --enable-autoscaling \
        --async
    

    更改下列內容:

    • PROJECT_ID:專案 ID
    • CLUSTER_2_ZONE:第二個叢集的區域,例如 us-east4-a
    • CLUSTER_2_NAME:第二個叢集的名稱,例如 gke-east
    • NODE_POOL_MACHINE_TYPE:節點集區的機型,例如 a3-highgpu-2g
    • NUM_NODES:節點集區中的節點數量,例如 3
    • MIN_NUM_NODES:節點集區中自動調度資源的節點數量下限,例如 1
    • MAX_NUM_NODES:節點集區中自動調度資源的節點數量上限,例如 10
  6. 在第二個叢集上取得憑證,並為 Hugging Face 權杖建立密鑰:

    gcloud container clusters get-credentials CLUSTER_2_NAME \
        --location CLUSTER_2_ZONE \
        --project=PROJECT_ID
    kubectl create secret generic hf-token --from-literal=token=HF_TOKEN
    

    請替換下列項目。如需其他變數的定義,請參閱先前的步驟:

    • HF_TOKEN:您的 Hugging Face 存取權杖

將叢集註冊至機群

  1. 將叢集註冊至專案的機群:

    gcloud container fleet memberships register CLUSTER_1_NAME \
        --gke-cluster CLUSTER_1_ZONE/CLUSTER_1_NAME \
        --location=global \
        --project=PROJECT_ID
    
    gcloud container fleet memberships register CLUSTER_2_NAME \
        --gke-cluster CLUSTER_2_ZONE/CLUSTER_2_NAME \
        --location=global \
        --project=PROJECT_ID
    

    請替換下列項目,並參閱先前的步驟,瞭解其他變數的定義:

    • CLUSTER_1_NAME:第一個叢集的名稱,例如 gke-west
    • CLUSTER_2_NAME:第二個叢集的名稱,例如 gke-east
  2. 啟用多叢集 Ingress 功能,並指定設定叢集:

    gcloud container fleet ingress enable \
        --config-membership=projects/PROJECT_ID/locations/global/memberships/CLUSTER_1_NAME
    

    請替換下列項目。如需其他變數的定義,請參閱先前的步驟:

    • PROJECT_ID:專案 ID
    • CLUSTER_1_NAME:第一個叢集的名稱,例如 gke-west

建立僅限 Proxy 的子網路

警告: Cloud de Confiance by S3NS 每個虛擬私有雲網路在每個區域只能有一個僅限 Proxy 的子網路。如果目標地區已包含具有 purpose=REGIONAL_MANAGED_PROXY 設定的僅限 Proxy 子網路,則無法建立 GLOBAL_MANAGED_PROXY 子網路。您必須先刪除現有的區域僅限 Proxy 子網路。刪除區域僅限 Proxy 的子網路會影響該區域中所有使用該子網路的區域 Envoy 型負載平衡器,因此請據此規劃變更。

  1. 在第一個叢集的區域中建立子網路:

    gcloud compute networks subnets create CLUSTER_1_REGION-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=CLUSTER_1_REGION \
        --network=default \
        --range=SUBNET_RANGE_1 \
        --project=PROJECT_ID
    

    更改下列內容:

    • PROJECT_ID:專案 ID
    • CLUSTER_1_REGION:第一個叢集的區域,例如 europe-west3
    • SUBNET_RANGE_1:第一個叢集區域中僅限 Proxy 子網路的子網路 IP 範圍,例如 10.0.0.0/23
  2. 在第二個叢集的區域中建立子網路:

    gcloud compute networks subnets create CLUSTER_2_REGION-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=CLUSTER_2_REGION \
        --network=default \
        --range=SUBNET_RANGE_2 \
        --project=PROJECT_ID
    

    更改下列內容:

    • PROJECT_ID:專案 ID
    • CLUSTER_2_REGION:第二個叢集的區域,例如 us-east4
    • SUBNET_RANGE_2:第二個叢集區域中僅限 Proxy 子網路的子網路 IP 範圍,例如 10.5.0.0/23

安裝必要的自訂資源

  1. 定義叢集的環境變數:

    CLUSTER1_CONTEXT="gke_PROJECT_ID_CLUSTER_1_ZONE_CLUSTER_1_NAME"
    CLUSTER2_CONTEXT="gke_PROJECT_ID_CLUSTER_2_ZONE_CLUSTER_2_NAME"
    

    更改下列內容:

    • PROJECT_ID:專案 ID
    • CLUSTER_1_ZONE:第一個叢集的區域,例如 europe-west3-c
    • CLUSTER_1_NAME:第一個叢集的名稱,例如 gke-west
    • CLUSTER_2_ZONE:第二個叢集的區域,例如 us-east4-a
    • CLUSTER_2_NAME:第二個叢集的名稱,例如 gke-east
  2. 在兩個叢集上安裝 InferencePool 和 InferenceObjective 自訂資源:

    kubectl apply -f https://github.com/kubernetes-sigs/gateway-api-inference-extension/releases/download/v1.0.1/manifests.yaml --context=$CLUSTER1_CONTEXT
    
    kubectl apply -f https://github.com/kubernetes-sigs/gateway-api-inference-extension/releases/download/v1.0.1/manifests.yaml --context=$CLUSTER2_CONTEXT
    

將資源部署至目標叢集

  1. 將模型伺服器部署至這兩個叢集:

    kubectl apply -f \
    https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/release-1.0/config/manifests/vllm/gpu-deployment.yaml \
    --context=$CLUSTER1_CONTEXT
    
    kubectl apply -f \
    https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/release-1.0/config/manifests/vllm/gpu-deployment.yaml \
    --context=$CLUSTER2_CONTEXT
    
  2. 將下列資訊清單儲存至名為 inference-objective.yaml 的檔案:

    apiVersion: inference.networking.x-k8s.io/v1alpha2
    kind: InferenceObjective
    metadata:
      name: food-review
    spec:
      priority: 10
      poolRef:
        name: llama3-8b-instruct
        group: "inference.networking.k8s.io"
    
  3. 將資訊清單套用至兩個叢集:

    kubectl apply -f inference-objective.yaml --context=$CLUSTER1_CONTEXT
    kubectl apply -f inference-objective.yaml --context=$CLUSTER2_CONTEXT
    
  4. 使用 Helm 將 InferencePool 資源部署至兩個叢集:

    helm install vllm-llama3-8b-instruct \
      --kube-context $CLUSTER1_CONTEXT \
      --set inferencePool.modelServers.matchLabels.app=vllm-llama3-8b-instruct \
      --set provider.name=gke \
      --set inferenceExtension.monitoring.gke.enabled=true \
      --version v1.0.1 \
      oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepool
    
    helm install vllm-llama3-8b-instruct \
      --kube-context $CLUSTER2_CONTEXT \
      --set inferencePool.modelServers.matchLabels.app=vllm-llama3-8b-instruct \
      --set provider.name=gke \
      --set inferenceExtension.monitoring.gke.enabled=true \
      --version v1.0.1 \
      oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepool
    
  5. 在兩個叢集中,將 InferencePool 資源標示為已匯出:

    kubectl annotate inferencepool vllm-llama3-8b-instruct networking.gke.io/export="True" \
        --context=$CLUSTER1_CONTEXT
    
    kubectl annotate inferencepool vllm-llama3-8b-instruct networking.gke.io/export="True" \
        --context=$CLUSTER2_CONTEXT
    

部署跨區域 Inference Gateway

  1. 將下列資訊清單儲存為 mygateway.yaml

    ---
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: cross-region-gateway
      namespace: default
    spec:
      gatewayClassName: gke-l7-cross-regional-internal-managed-mc
      addresses:
      -   type: networking.gke.io/ephemeral-ipv4-address/europe-west3
        value: "europe-west3"
      -   type: networking.gke.io/ephemeral-ipv4-address/us-east4
        value: "us-east4"
      listeners:
      -   name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          -   kind: HTTPRoute
          namespaces:
            from: All
    ---
    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: vllm-llama3-8b-instruct-default
    spec:
      parentRefs:
      -   name: cross-region-gateway
        kind: Gateway
      rules:
      -   backendRefs:
        -   group: networking.gke.io
          kind: GCPInferencePoolImport
          name: vllm-llama3-8b-instruct
    ---
    kind: HealthCheckPolicy
    apiVersion: networking.gke.io/v1
    metadata:
      name: health-check-policy
      namespace: default
    spec:
      targetRef:
        group: "networking.gke.io"
        kind: GCPInferencePoolImport
        name: vllm-llama3-8b-instruct
      default:
        config:
          type: HTTP
          httpHealthCheck:
              requestPath: /health
              port: 8000
    
  2. 將資訊清單套用至設定叢集:

    kubectl apply -f mygateway.yaml --context=CLUSTER1_CONTEXT
    

    更改下列內容:

    • CLUSTER1_CONTEXT:第一個叢集的情境,例如 gke_my-project_europe-west3-c_gke-west

啟用自訂指標回報功能

  1. 建立名為 metrics.yaml 的檔案,並加入以下內容:

    apiVersion: autoscaling.gke.io/v1beta1
    kind: AutoscalingMetric
    metadata:
      name: gpu-cache
      namespace: default
    spec:
      selector:
        matchLabels:
          app: vllm-llama3-8b-instruct
      endpoints:
      -   port: 8000
        path: /metrics
        metrics:
        -   name: vllm:kv_cache_usage_perc
          exportName: kv-cache
        -   name: vllm:gpu_cache_usage_perc
          exportName: kv-cache-old
    
  2. 針對每個叢集套用指標設定:

    kubectl apply -f metrics.yaml --context=CLUSTER1_CONTEXT
    kubectl apply -f metrics.yaml --context=CLUSTER2_CONTEXT
    

    如要瞭解 CLUSTER1_CONTEXTCLUSTER2_CONTEXT 的定義,請參閱安裝必要的自訂資源

設定負載平衡政策

本節說明如何設定負載平衡政策。這項政策會根據自訂指標和地區偏好設定,定義流量在推論集區的分配方式。下列設定會將 us-east4 設為偏好區域。只有當 us-east4 區域的 gke.named_metrics.kv-cache 自訂指標達到 80% 的使用率時,流量才會溢流至其他區域。

  • 如果是 vLLM v0.10.2 以上版本,請使用 gke.named_metrics.kv-cache 指標。
  • 如果是較舊版本,請使用 gke.named_metrics.kv-cache-old 指標。
  1. 建立名為 backend-policy.yaml 的檔案,並加入以下內容:

    kind: GCPBackendPolicy
    apiVersion: networking.gke.io/v1
    metadata:
      name: my-backend-policy
    spec:
      targetRef:
        group: "networking.gke.io"
        kind: GCPInferencePoolImport
        name: vllm-llama3-8b-instruct
      default:
        timeoutSec: 600
        balancingMode: CUSTOM_METRICS
        trafficDuration: LONG
        customMetrics:
        -   name: gke.named_metrics.kv-cache
          maxUtilizationPercent: 80
          dryRun: false
        scopes:
        -   selector:
            gke.io/region: "us-east4"
          backendPreference: PREFERRED
    
  2. 套用新政策:

    kubectl apply -f backend-policy.yaml --context=CLUSTER1_CONTEXT
    

    CLUSTER1_CONTEXT 替換為第一個叢集的內容,例如 gke_my-project_europe-west3-c_gke-west

設定自動調度資源功能

為確保每個叢集都能處理不斷增加的負載,避免流量溢出至其他區域,您需要為模型伺服器部署作業設定 Horizontal-Pod-Autoscaler (HPA)。

重要設定原則

  • 使用相同的自訂指標:應將 HPA 設為根據您在 GCPBackendPolicy 中使用的相同自訂指標,調整多叢集推論閘道 (例如 vllm:kv_cache_usage_perc) 的資源配置。這種做法可確保負載平衡和資源調度決策都是根據推論伺服器發出的相同信號。所選指標的值必須介於 0 到 1 之間,代表使用率。如果指標值大於 1,表示負載平衡器使用率為 100%,可能會導致非預期的路由行為。

  • 設定較低的 HPA 目標:HPA 設定中的指標目標值必須低於 maxUtilizationPercent 設定中定義的 GCPBackendPolicy。將 HPA 的目標使用率調低 (例如,HPA 在平均使用率達到 50% 時進行資源調度),即可在負載平衡器的門檻 (例如使用率達到 80%) 之前,讓叢集新增更多副本。這種做法有助於在偏好區域內盡量提高容量。此外,如果使用率目標較低,系統就會預留彈性跨區域高可用性,以防目前區域的流量接近上限,有助於避免流量過早溢出。

  1. 授予使用者權限,使其能夠建立必要的授權角色:

    kubectl create clusterrolebinding cluster-admin-binding \
        --clusterrole cluster-admin --user "$(gcloud config get-value account)" --context=CLUSTER1_CONTEXT
    
    kubectl create clusterrolebinding cluster-admin-binding \
        --clusterrole cluster-admin --user "$(gcloud config get-value account)" --context=CLUSTER2_CONTEXT
    

    CLUSTER1_CONTEXTCLUSTER2_CONTEXT 變數是在「安裝必要自訂資源」一節中定義。

  2. 針對每個叢集套用資訊清單:

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml --context=CLUSTER1_CONTEXT
    
    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml --context=CLUSTER2_CONTEXT
    
  3. 允許 custom-metrics-stackdriver-adapter 服務帳戶讀取 Cloud Monitoring 指標:

    PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format="value(projectNumber)")
    
    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.s3ns.svc.id.goog/subject/ns/custom-metrics/sa/custom-metrics-stackdriver-adapter
    

    PROJECT_ID 替換為您的專案 ID

  4. 將下列資訊清單儲存至名為 pod-monitoring.yaml 的檔案:

    apiVersion: monitoring.googleapis.com/v1
    kind: PodMonitoring
    metadata:
      name: inference-server-podmon
    spec:
      selector:
        matchLabels:
          app: vllm-llama3-8b-instruct
      endpoints:
      -   port: 8000
        path: /metrics
        interval: 5s
    
  5. 將資訊清單套用至兩個叢集:

    kubectl apply -f pod-monitoring.yaml --context=CLUSTER1_CONTEXT
    kubectl apply -f pod-monitoring.yaml --context=CLUSTER2_CONTEXT
    
  6. 將下列資訊清單儲存至名為 hpa.yaml 的檔案:

    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: inference-server-hpa
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: vllm-llama3-8b-instruct
      minReplicas: 1
      maxReplicas: 10
      metrics:
      -   type: Pods
        pods:
          metric:
            name: prometheus.googleapis.com|vllm:gpu_cache_usage_perc|gauge
          target:
            type: AverageValue
            averageValue: "0.5"
    
  7. 將資訊清單套用至兩個叢集:

    kubectl apply -f hpa.yaml --context=CLUSTER1_CONTEXT
    kubectl apply -f hpa.yaml --context=CLUSTER2_CONTEXT
    

驗證 Deployment

  1. 取得閘道 IP 位址:

    export GW_IP=$(kubectl get gateway/cross-region-gateway -n default --context=CLUSTER1_CONTEXT -o jsonpath='{.status.addresses[0].value}')
    
    echo ${GW_IP}
    

    CLUSTER1_CONTEXT 變數是在「安裝必要自訂資源」一節中定義。

  2. 在臨時 Pod 中啟動互動式 sh 工作階段:

    kubectl run -it --rm --image=curlimages/curl curly --context=CLUSTER1_CONTEXT -- /bin/sh
    

    CLUSTER1_CONTEXT 變數是在「安裝必要自訂資源」一節中定義。

  3. curly Pod 內部傳送測試要求:

    curl -i -X POST <var>GW_IP</var>:80/v1/completions \
    -H 'Content-Type: application/json' \
    -d '{
      "model": "food-review-1",
      "prompt": "What is the best pizza in the world?",
      "max_tokens": 100,
      "temperature": 0
    }'
    

    GW_IP 替換為上一個步驟中的閘道 IP 位址。

對閘道執行負載測試

  1. 使用相同虛擬私有雲網路中的負載產生器,對閘道 IP 位址套用持續負載。

  2. 首先,請從您預期偏好區域 (us-east4) 可處理的適中負載開始。

  3. 逐漸提高負載測試的要求比率或並行數量。

  4. 執行負載測試時,請在 Cloud de Confiance 控制台或使用 kubectl 監控系統:

    • Pod 調度 (HPA):檢查兩個叢集中的 vllm-llama3-8b-instruct Deployment 內 Pod 數量。
    • 節點調度 (叢集自動配置器):監控兩個叢集中的 h100 節點集區內的節點數量。
    • 自訂指標:在兩個叢集的模型伺服器部署作業中,於 Monitoring 監控 vllm:kv_cache_usage_perc 指標 (適用於 vllm v0.10.2 以上版本) 或 vllm:gpu_cache_usage_perc 指標 (適用於 vllm v.0.10.2 以下版本)。
    • 負載平衡器指標:在 Monitoring 中檢查與 cross-region-gateway 相關聯的負載平衡器指標。

隨著負載增加,us-east4中的使用率也會提高。當 gke-east 叢集中的 HPA 擴大,且平均用量接近 GCPBackendPolicy 中定義的 maxUtilization 值 (80%) 時,負載平衡器就會開始將要求路由至 europe-west3 中的 gke-west 叢集。

後續步驟