設定多叢集 GKE Inference Gateway

本文說明如何設定多叢集 Google Kubernetes Engine (GKE) 推論閘道,在多個 GKE 叢集之間智慧地平衡 AI/ML 推論工作負載,這些叢集可跨越多個區域。這項設定會使用 Gateway API、多叢集 Ingress 和 InferencePool 與 InferenceObjective 等自訂資源,提升模型服務部署作業的可擴充性、確保高可用性,並盡量充分運用資源。

如要瞭解本文內容,請先熟悉下列概念:

本文件適用於下列角色:

  • 機器學習工程師、平台管理員和營運人員,或想使用 GKE 的容器自動化調度管理功能,提供 AI/機器學習工作負載的資料和 AI 專家。
  • 與 GKE 網路互動的雲端架構師或網路專家。

如要進一步瞭解Google Cloud 內容中提及的常見角色和範例工作,請參閱「常見的 GKE Enterprise 使用者角色和工作」。

事前準備

開始之前,請確認您已完成下列工作:

  • 啟用 Google Kubernetes Engine API。
  • 啟用 Google Kubernetes Engine API
  • 如要使用 Google Cloud CLI 執行這項工作,請安裝初始化 gcloud CLI。如果您先前已安裝 gcloud CLI,請執行 gcloud components update 指令,取得最新版本。較舊的 gcloud CLI 版本可能不支援執行本文件中的指令。
  • 啟用 Compute Engine API、Kubernetes Engine API、Model Armor 和 Network Services API。

    前往「啟用 API 存取權」,然後按照操作說明進行。

  • 啟用 Autoscaling API。

    前往 Autoscaling API,然後按照指示操作。

  • 啟用 GKE Hub API。

    前往 GKE Hub API,然後按照指示操作。

  • Hugging Face 先決條件:

    • 如果沒有 Hugging Face 帳戶,請先建立一個。
    • 要求並取得 Hugging Face 上 Llama 3.1 模型的存取權。
    • 在 Hugging Face 的模型頁面簽署授權同意聲明協議。
    • 產生至少具備 Read 權限的 Hugging Face 存取權杖。

需求條件

  • 確認專案有足夠的 H100 GPU 配額。詳情請參閱「規劃 GPU 配額」和「分配配額」。
  • 使用 GKE 1.34.1-gke.1127000 以上版本。
  • 使用 gcloud CLI 480.0.0 以上版本。
  • 節點服務帳戶必須具有寫入指標至 Autoscaling API 的權限。
  • 您必須在專案中具備下列 IAM 角色:roles/container.adminroles/iam.serviceAccountAdmin

多重連接埠和 NEG 限制

在多叢集設定中部署多個 InferencePool 資源時,請注意 Google Cloud 後端服務 NEG 限制。每個區域中的每個通訊埠都會建立專屬的 NEG。舉例來說,如果地區叢集有三個區域,且 InferencePool 設定了八個通訊埠,就會使用 24 個 NEG。由於每個後端服務最多只能有 50 個 NEG,因此您最多只能從兩個叢集匯總這個特定 InferencePool,否則就會達到上限。

設定多叢集推論閘道

如要設定多叢集 GKE Inference Gateway,請按照下列步驟操作:

建立叢集和節點集區

如要代管 AI/機器學習推論工作負載,並啟用跨區域負載平衡,請在不同區域中建立兩個 GKE 叢集,每個叢集都包含 H100 GPU 節點集區。

  1. 建立第一個叢集:

    gcloud container clusters create CLUSTER_1_NAME \
        --region LOCATION \
        --project=PROJECT_ID \
        --gateway-api=standard \
        --release-channel "rapid" \
        --cluster-version=GKE_VERSION \
        --machine-type="MACHINE_TYPE" \
        --disk-type="DISK_TYPE" \
        --enable-managed-prometheus --monitoring=SYSTEM,DCGM \
        --hpa-profile=performance \
        --async # Allows the command to return immediately
    

    更改下列內容:

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

    gcloud container node-pools create NODE_POOL_NAME \
        --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 \
        --async # Allows the command to return immediately
    

    更改下列內容:

    • NODE_POOL_NAME:節點集區的名稱,例如 h100
    • PROJECT_ID:您的專案 ID。
    • CLUSTER_1_ZONE:第一個叢集的可用區,例如 europe-west3-c
    • CLUSTER_1_NAME:第一個叢集的名稱,例如 gke-west
    • NODE_POOL_MACHINE_TYPE:節點集區的機型,例如 a3-highgpu-2g
    • NUM_NODES:節點集區中的節點數量,例如 3
  3. 取得憑證:

    gcloud container clusters get-credentials CLUSTER_1_NAME \
        --location CLUSTER_1_ZONE \
        --project=PROJECT_ID
    

    更改下列內容:

    • PROJECT_ID:您的專案 ID。
    • CLUSTER_1_NAME:第一個叢集的名稱,例如 gke-west
    • CLUSTER_1_ZONE:第一個叢集的可用區,例如 europe-west3-c
  4. 在第一個叢集上,為 Hugging Face 權杖建立密鑰:

    kubectl create secret generic hf-token \
        --from-literal=token=HF_TOKEN
    

    HF_TOKEN 換成你的 Hugging Face 存取權杖。

  5. 在與第一個叢集不同的區域中建立第二個叢集:

    gcloud container clusters create gke-east --region LOCATION \
        --project=PROJECT_ID \
        --gateway-api=standard \
        --release-channel "rapid" \
        --cluster-version=GKE_VERSION \
        --machine-type="MACHINE_TYPE" \
        --disk-type="DISK_TYPE" \
        --enable-managed-prometheus \
        --monitoring=SYSTEM,DCGM \
        --hpa-profile=performance \
        --async # Allows the command to return immediately while the
    cluster is created in the background.
    

    更改下列內容:

    • LOCATION:第二個叢集的區域。這個區域必須與第一個叢集不同。例如:us-east4
    • PROJECT_ID:您的專案 ID。
    • GKE_VERSION:要使用的 GKE 版本,例如 1.34.1-gke.1127000
    • MACHINE_TYPE:叢集節點的機型,例如 c2-standard-16
    • DISK_TYPE:叢集節點的磁碟類型,例如 pd-standard
  6. 為第二個叢集建立 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 \
        --async # Allows the command to return immediately
    

    更改下列內容:

    • PROJECT_ID:您的專案 ID。
    • CLUSTER_2_ZONE:第二個叢集的可用區,例如 us-east4-a
    • CLUSTER_2_NAME:第二個叢集的名稱,例如 gke-east
    • NODE_POOL_MACHINE_TYPE:節點集區的機型,例如 a3-highgpu-2g
    • NUM_NODES:節點集區中的節點數量,例如 3
  7. 針對第二個叢集,取得憑證並建立 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
    

    更改下列內容:

    • CLUSTER_2_NAME:第二個叢集的名稱,例如 gke-east
    • CLUSTER_2_ZONE:第二個叢集的可用區,例如 us-east4-a
    • PROJECT_ID:您的專案 ID。
    • HF_TOKEN:您的 Hugging Face 存取權杖。

將叢集註冊至機群

如要啟用多叢集功能 (例如多叢集 GKE Inference Gateway),請向機群註冊叢集。

  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_1_ZONE:第一個叢集的可用區,例如 europe-west3-c
    • PROJECT_ID:您的專案 ID。
    • CLUSTER_2_NAME:第二個叢集的名稱,例如 gke-east
    • CLUSTER_2_ZONE:第二個叢集的可用區,例如 us-east4-a
  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 的子網路

如果是內部閘道,請在每個區域中建立僅限 Proxy 的子網路。內部閘道的 Envoy Proxy 會使用這些專屬子網路,處理虛擬私有雲網路內的流量。

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

    gcloud compute networks subnets create CLUSTER_1_REGION-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=CLUSTER_1_REGION \
        --network=default \
        --range=10.0.0.0/23 \
        --project=PROJECT_ID
    
  2. 在第二個叢集的區域中建立子網路:

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

    更改下列內容:

    • PROJECT_ID:您的專案 ID。
    • CLUSTER_1_REGION:第一個叢集的區域,例如 europe-west3
    • CLUSTER_2_REGION:第二個叢集的區域,例如 us-east4

安裝必要的 CRD

多叢集 GKE Inference Gateway 使用 InferencePool 和 InferenceObjective 等自訂資源。GKE Gateway API 控制器會管理 InferencePool Custom Resource Definition (CRD)。不過,您必須在叢集上手動安裝 Alpha 版的 InferenceObjective CRD。

  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. 在兩個叢集上安裝 InferenceObjective CRD:

    kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/crd/bases/inference.networking.x-k8s.io_inferenceobjectives.yaml --context=$CLUSTER1_CONTEXT
    
    kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/crd/bases/inference.networking.x-k8s.io_inferenceobjectives.yaml --context=$CLUSTER2_CONTEXT
    

將資源部署至目標叢集

如要在每個叢集上提供 AI/機器學習推論工作負載,請部署必要資源,例如模型伺服器和 InferenceObjective 自訂資源。

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

    kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/manifests/vllm/gpu-deployment.yaml --context=CLUSTER1_CONTEXT
    
    kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/manifests/vllm/gpu-deployment.yaml --context=CLUSTER2_CONTEXT
    

    更改下列內容:

    • CLUSTER1_CONTEXT:第一個叢集的情境,例如 gke_my-project_europe-west3-c_gke-west
    • CLUSTER2_CONTEXT:第二個叢集的情境,例如 gke_my-project_us-east4-a_gke-east
  2. 將 InferenceObjective 資源部署至這兩個叢集。將下列範例資訊清單儲存至名為 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
    

    更改下列內容:

    • CLUSTER1_CONTEXT:第一個叢集的情境,例如 gke_my-project_europe-west3-c_gke-west
    • CLUSTER2_CONTEXT:第二個叢集的情境,例如 gke_my-project_us-east4-a_gke-east
  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.1.0 \
      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.1.0 \
      oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepool
    

    更改下列內容:

    • CLUSTER1_CONTEXT:第一個叢集的情境,例如 gke_my-project_europe-west3-c_gke-west
    • CLUSTER2_CONTEXT:第二個叢集的情境,例如 gke_my-project_us-east4-a_gke-east
  5. 在兩個叢集上,將 InferencePool 資源標示為已匯出。這個註解可讓設定叢集匯入 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
    

    更改下列內容:

    • CLUSTER1_CONTEXT:第一個叢集的情境,例如 gke_my-project_europe-west3-c_gke-west
    • CLUSTER2_CONTEXT:第二個叢集的情境,例如 gke_my-project_us-east4-a_gke-east

將資源部署至設定叢集

如要定義流量在所有已註冊叢集的 InferencePool 資源中,如何進行路由和負載平衡,請部署 GatewayHTTPRouteHealthCheckPolicy 資源。您只能將這些資源部署至指定的設定叢集,也就是本文中的 gke-west

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

    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    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
    ---
    apiVersion: gateway.networking.k8s.io/v1
    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
    ---
    apiVersion: networking.gke.io/v1
    kind: HealthCheckPolicy
    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 mcig.yaml --context=CLUSTER1_CONTEXT
    

    CLUSTER1_CONTEXT 替換為第一個叢集 (設定叢集) 的環境,例如 gke_my-project_europe-west3-c_gke-west

啟用自訂指標回報功能

如要啟用自訂指標報表功能並改善跨區域負載平衡,請從所有叢集匯出 KV 快取用量指標。負載平衡器會使用這項匯出的 KV 快取用量資料做為自訂負載信號。使用這項自訂負載信號,可根據每個叢集的實際工作負載,制定更智慧的負載平衡決策。

  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 # For vLLM versions v0.10.2 and newer
          exportName: kv-cache
        - name: vllm:gpu_cache_usage_perc # For vLLM versions v0.6.2 and newer
          exportName: kv-cache-old
    
  2. 將指標設定套用至這兩個叢集:

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

    更改下列內容:

    • CLUSTER1_CONTEXT:第一個叢集的情境,例如 gke_my-project_europe-west3-c_gke-west
    • CLUSTER2_CONTEXT:第二個叢集的情境,例如 gke_my-project_us-east4-a_gke-east

設定負載平衡政策

如要最佳化 AI/機器學習推論要求在 GKE 叢集中的分配方式,請設定負載平衡政策。選擇合適的平衡模式有助於確保資源使用效率、避免個別叢集過載,並提升推論服務的整體效能和回應速度。

設定逾時

如果要求預計會持續較長時間,請為負載平衡器設定較長的逾時時間。在 GCPBackendPolicy 中,將 timeoutSec 欄位設為至少是預估 P99 要求延遲時間的兩倍。

舉例來說,以下資訊清單會將負載平衡器逾時設為 100 秒。

apiVersion: networking.gke.io/v1
kind: GCPBackendPolicy
metadata:
  name: my-backend-policy
spec:
  targetRef:
    group: "networking.gke.io"
    kind: GCPInferencePoolImport
    name: vllm-llama3-8b-instruct
  default:
    timeoutSec: 100
    balancingMode: CUSTOM_METRICS
    trafficDuration: LONG
    customMetrics:
      - name: gke.named_metrics.kv-cache
        dryRun: false
        maxUtilizationPercent: 60

詳情請參閱「多叢集 Gateway 限制」一節。

由於自訂指標處理中要求負載平衡模式互斥,請在 GCPBackendPolicy 中只設定其中一種模式。

為部署項目選擇負載平衡模式。

自訂指標

如要達到最佳負載平衡,請先將目標使用率設為 60%。如要達成這個目標,請在 GCPBackendPolicycustomMetrics 設定中設定 maxUtilizationPercent: 60

  1. 建立名為 backend-policy.yaml 的檔案,並在其中加入下列內容,啟用以 kv-cache 自訂指標為依據的負載平衡:

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

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

    CLUSTER1_CONTEXT 替換為第一個叢集的環境,例如 gke_my-project-europe-west3-c-gke-west

處理中的要求

如要使用「處理中」平衡模式,請估算每個後端可處理的處理中要求數量,並明確設定容量值。

  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:
        balancingMode: IN_FLIGHT
        trafficDuration: LONG
        maxInFlightRequestsPerEndpoint: 1000
        dryRun: false
    
  2. 套用新政策:

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

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

驗證 Deployment

如要驗證內部負載平衡器,您必須從虛擬私有雲網路內傳送要求,因為內部負載平衡器使用私人 IP 位址。在其中一個叢集中執行暫時性 Pod,從虛擬私有雲網路傳送要求,並驗證內部負載平衡器:

  1. 從新的殼層取得閘道 IP 位址:

    GW_IP=$(kubectl get gateway/cross-region-gateway -n default --context=$CLUSTER1_CONTEXT -o jsonpath='{.status.addresses[0].value}')
    
  2. 從叢集內的臨時 Pod 傳送測試要求:

    kubectl run -it --rm --image=curlimages/curl curly --context=$CLUSTER1_CONTEXT -- \
      curl -i -X POST ${GW_IP}: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
      }'
    

後續步驟