設定彈性跨區域高可用性

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

如要進一步瞭解 GKE 多叢集 Inference Gateway,請參閱「關於 GKE 多叢集 Inference Gateway」。

事前準備

  1. 啟用 Google Kubernetes Engine API。

    啟用 Google Kubernetes Engine API

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

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

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

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

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

  7. 確認您在專案中具備 roles/container.admin 和 roles/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_CONTEXT 和 CLUSTER2_CONTEXT 的定義,請參閱「安裝必要的自訂資源」。

設定負載平衡政策

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

  • 如果是 vLLM 0.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

設定自動調度資源功能

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

重要設定原則

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

  • 設定較低的 HPA 目標:HPA 設定中的指標目標值必須低於 GCPBackendPolicy 中定義的 maxUtilizationPercent 設定。將 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_CONTEXT 和 CLUSTER2_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 v0.10.2 以下版本)。
    • 負載平衡器指標:在 Monitoring 中檢查與 cross-region-gateway 相關聯的負載平衡器指標。

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

後續步驟