本文說明如何設定 Kubernetes Gateway API 和 GKE Inference Gateway,管理 Google Kubernetes Engine (GKE) 上多個 Ray Serve 叢集的推論要求。這項設定可讓您集中管理多個團隊的流量、在不同區域分配工作負載以提高容量,以及根據要求主體內容實作模型感知型路徑。
使用 GKE Inference Gateway 和 Ray Serve 的優點
使用 GKE Inference Gateway 和 Ray Serve 可享有下列優點:
- 路徑轉送:為每個 RayService 設定路徑前置字元,然後透過一個 Gateway 轉送至多個 RayService。
- 如要進一步瞭解如何設定路徑前置字串規則,請參閱 Gateway API 說明文件。
- 模型感知型轉送:根據要求主體選擇要轉送的 RayService,例如從 OpenAI API JSON 要求中擷取要求的模型。
- 控管:要求使用 API 金鑰才能使用服務,或使用 Apigee 進行驗證和 API 管理,強制執行使用者配額。
- 多區域:使用 RayServices 在多個 GKE 叢集之間分配流量,透過多叢集閘道提高可用性或容量。
- 關注點分離:使用可由不同團隊管理、遵循不同推出程序,以及在不同拓撲上執行的獨立 RayService。
- 安全性:使用 Gateway 做為 SSL 終止器,協助保護使用者透過網際網路傳輸的流量。詳情請參閱「閘道安全性」。
如要設定轉送,您需要部署 Gateway、HTTPRoute 和 RayService。KubeRay 通常會為每個目標 Ray 叢集建立 Kubernetes Service。Ray Serve 會在叢集中分散要求負載,不需要建立 InferencePool 或 Endpoint Picker。
在 GKE 上使用 Ray Serve 進行模型感知式路由
以模型為依據的路由是由以主體為依據的路由擴充功能啟用。您可以根據使用者要求中指定的模型名稱,將流量導向至不同的 RayService,這樣一來,單一端點就能服務多個 Ray 叢集中託管的模型。使用者可輕鬆存取,應用程式開發人員則可控管每個 Ray 端點的設定。
如要設定模型感知路徑,請部署下列主要元件:
- 以主體為基礎的路由器擴充功能,可從 JSON 酬載擷取模型名稱。這個路由器擴充功能是使用 Helm 部署。
- GKE Gateway (第 7 層區域性內部應用程式負載平衡器),用於處理傳入流量。
- HTTPRoute 規則,可使用路由器擴充功能填入的標頭,將流量導向正確的 Ray 服務。
- 多個 Ray Serve 叢集,用於管理孤立模型的生命週期和自動調度資源。
事前準備
開始之前,請務必先完成下列工作:
- 啟用 Google Kubernetes Engine API。 啟用 Google Kubernetes Engine API
- 如要使用 Google Cloud CLI 執行這項工作,請安裝並初始化 gcloud CLI。如果您先前已安裝 gcloud CLI,請執行
gcloud components update指令,取得最新版本。較舊的 gcloud CLI 版本可能不支援執行本文件中的指令。
- 確認已安裝 Helm。
- 如果您還沒有 Hugging Face 帳戶,請建立一個。
- 請確認您擁有 Hugging Face 權杖。
準備環境
設定環境變數:
export CLUSTER=$(whoami)-ray-bbr
export PROJECT_ID=$(gcloud config get-value project)
export LOCATION=us-central1-b
export REGION=us-central1
export HUGGING_FACE_TOKEN=YOUR_HUGGING_FACE_TOKEN
將 YOUR_HUGGING_FACE_TOKEN 替換為您的 Hugging Face 存取權杖。
準備基礎架構
在本節中,您將設定啟用 Ray 和 Gateway 的 GKE 叢集,並使用 L4 GPU。
建立叢集,並啟用 Ray Operator 和 Gateway API:
gcloud container clusters create ${CLUSTER} \ --project ${PROJECT_ID} \ --location ${LOCATION} \ --cluster-version 1.35 \ --gateway-api standard \ --addons HttpLoadBalancing,RayOperator \ --enable-ray-cluster-logging \ --enable-ray-cluster-monitoring \ --machine-type e2-standard-4為模型工作負載建立 GPU 節點集區:
gcloud container node-pools create gpu-pool \ --cluster=${CLUSTER} \ --location=${LOCATION} \ --accelerator="type=nvidia-l4,count=1,gpu-driver-version=latest" \ --machine-type=g2-standard-8 \ --num-nodes=4為區域性內部應用程式負載平衡器建立 Proxy 專用子網路,這是以主體為準的路由功能所需:
gcloud compute networks subnets create bbr-proxy-only-subnet \ --purpose=REGIONAL_MANAGED_PROXY \ --role=ACTIVE \ --region=${REGION} \ --network=default \ --range=192.168.10.0/24部署 Hugging Face 密鑰:
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HUGGING_FACE_TOKEN}
部署以主體為依據的路由器,進行模型感知路由
以主體為基礎的路由器擴充功能會攔截要求、剖析 JSON 主體,並將模型欄位擷取至 X-Gateway-Model-Name 標頭。
建立名為
helm-values.yaml的檔案,並加入以下內容:bbr: plugins: - type: "body-field-to-header" name: "openai-model-extractor" json: field_name: "model" header_name: "X-Gateway-Model-Name"使用 Helm 安裝以主體為依據的路由器:
helm install body-based-router \ oci://registry.k8s.io/gateway-api-inference-extension/charts/body-based-routing \ --version v1.4.0 \ --set provider.name=gke \ --set inferenceGateway.name=ray-multi-model-gateway \ --values helm-values.yaml
部署 RayService
如要部署模型,請套用 RayService 資訊清單。每個資訊清單都會定義執行特定 LLM 的 Ray 叢集。
建立名為
gemma-2b-it.yaml的檔案,並加入以下內容:apiVersion: ray.io/v1 kind: RayService metadata: name: gemma-2b-it spec: serveConfigV2: | applications: - name: llm_app route_prefix: "/" import_path: ray.serve.llm:build_openai_app args: llm_configs: - model_loading_config: model_id: gemma-2b-it model_source: google/gemma-2b-it accelerator_type: L4 log_engine_metrics: true deployment_config: autoscaling_config: min_replicas: 2 max_replicas: 2 health_check_period_s: 600 health_check_timeout_s: 300 rayClusterConfig: headGroupSpec: rayStartParams: dashboard-host: "0.0.0.0" num-cpus: "0" template: spec: containers: - name: ray-head image: rayproject/ray-llm:2.54.0-py311-cu128 resources: limits: memory: "8Gi" ephemeral-storage: "32Gi" requests: cpu: "2" memory: "8Gi" ephemeral-storage: "32Gi" ports: - containerPort: 6379 name: gcs-server - containerPort: 8265 name: dashboard - containerPort: 10001 name: client - containerPort: 8000 name: serve env: - name: RAY_SERVE_THROUGHPUT_OPTIMIZED value: "1" - name: RAY_SERVE_ENABLE_HA_PROXY value: "1" - name: HUGGING_FACE_HUB_TOKEN valueFrom: secretKeyRef: name: hf-secret key: hf_api_token rayVersion: 2.54.0 workerGroupSpecs: - replicas: 2 minReplicas: 2 maxReplicas: 2 groupName: gpu-group rayStartParams: {} template: spec: containers: - name: llm image: rayproject/ray-llm:2.54.0-py311-cu128 env: - name: RAY_SERVE_THROUGHPUT_OPTIMIZED value: "1" - name: RAY_SERVE_ENABLE_HA_PROXY value: "1" - name: HUGGING_FACE_HUB_TOKEN valueFrom: secretKeyRef: name: hf-secret key: hf_api_token resources: limits: nvidia.com/gpu: "1" ephemeral-storage: "24Gi" requests: cpu: "6" memory: "24Gi" nvidia.com/gpu: "1" ephemeral-storage: "24Gi" nodeSelector: cloud.google.com/gke-accelerator: nvidia-l4建立名為
qwen2.5-3b.yaml的檔案,並加入以下內容:apiVersion: ray.io/v1 kind: RayService metadata: name: qwen-25-3b spec: serveConfigV2: | applications: - name: llm_app route_prefix: "/" import_path: ray.serve.llm:build_openai_app args: llm_configs: - model_loading_config: model_id: qwen-2.5-3b model_source: Qwen/Qwen2.5-3B accelerator_type: L4 log_engine_metrics: true deployment_config: autoscaling_config: min_replicas: 2 max_replicas: 2 health_check_period_s: 600 health_check_timeout_s: 300 rayClusterConfig: headGroupSpec: rayStartParams: dashboard-host: "0.0.0.0" num-cpus: "0" template: spec: containers: - name: ray-head image: rayproject/ray-llm:2.54.0-py311-cu128 resources: limits: memory: "8Gi" ephemeral-storage: "32Gi" requests: cpu: "2" memory: "8Gi" ephemeral-storage: "32Gi" ports: - containerPort: 6379 name: gcs-server - containerPort: 8265 name: dashboard - containerPort: 10001 name: client - containerPort: 8000 name: serve env: - name: RAY_SERVE_THROUGHPUT_OPTIMIZED value: "1" - name: RAY_SERVE_ENABLE_HA_PROXY value: "1" - name: HUGGING_FACE_HUB_TOKEN valueFrom: secretKeyRef: name: hf-secret key: hf_api_token rayVersion: 2.54.0 workerGroupSpecs: - replicas: 2 minReplicas: 2 maxReplicas: 2 groupName: gpu-group rayStartParams: {} template: spec: containers: - name: llm image: rayproject/ray-llm:2.54.0-py311-cu128 env: - name: RAY_SERVE_THROUGHPUT_OPTIMIZED value: "1" - name: RAY_SERVE_ENABLE_HA_PROXY value: "1" - name: HUGGING_FACE_HUB_TOKEN valueFrom: secretKeyRef: name: hf-secret key: hf_api_token resources: limits: nvidia.com/gpu: "1" ephemeral-storage: "24Gi" requests: cpu: "6" memory: "24Gi" nvidia.com/gpu: "1" ephemeral-storage: "24Gi" nodeSelector: cloud.google.com/gke-accelerator: nvidia-l4部署模型:
kubectl apply -f gemma-2b-it.yaml kubectl apply -f qwen2.5-3b.yaml
設定健康狀態檢查
為確保負載平衡器能準確監控 Ray 工作人員的健康狀態,您必須套用 HealthCheckPolicy 資源。
建立名為
healthcheck-policy.yaml的檔案,並加入以下內容:apiVersion: networking.gke.io/v1 kind: HealthCheckPolicy metadata: name: gemma-serve-healthcheck namespace: default spec: default: checkIntervalSec: 5 timeoutSec: 5 healthyThreshold: 2 unhealthyThreshold: 2 config: type: HTTP httpHealthCheck: port: 8000 requestPath: /-/healthz targetRef: group: "" kind: Service name: gemma-2b-it-serve-svc --- apiVersion: networking.gke.io/v1 kind: HealthCheckPolicy metadata: name: qwen-serve-healthcheck namespace: default spec: default: checkIntervalSec: 5 timeoutSec: 5 healthyThreshold: 2 unhealthyThreshold: 2 config: type: HTTP httpHealthCheck: port: 8000 requestPath: /-/healthz targetRef: group: "" kind: Service name: qwen-25-3b-serve-svc套用健康狀態檢查政策:
kubectl apply -f healthcheck-policy.yaml
設定轉送
如要設定轉送,請套用 Gateway 和 HTTPRoute 資訊清單。
HTTPRoute 包含與 X-Gateway-Model-Name 標頭 (由以主體為基礎的路由器填入) 相符的規則,可將流量轉送至適當的 Ray 服務。
建立名為
gateway.yaml的檔案,並加入以下內容:apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: ray-multi-model-gateway namespace: default spec: gatewayClassName: gke-l7-rilb listeners: - allowedRoutes: namespaces: from: Same name: http port: 80 protocol: HTTP --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: ray-multi-model-route spec: parentRefs: - name: ray-multi-model-gateway rules: - matches: - headers: - type: Exact name: X-Gateway-Model-Name value: gemma-2b-it # Must match model named in JSON request! path: type: PathPrefix value: / backendRefs: - name: gemma-2b-it-serve-svc # Ray service name plus "-serve-svc". kind: Service port: 8000 - matches: - headers: - type: Exact name: X-Gateway-Model-Name value: qwen-2.5-3b # Matches another extracted model name path: type: PathPrefix value: / backendRefs: - name: qwen-25-3b-serve-svc # Target Ray Service. kind: Service port: 8000套用閘道和路徑:
kubectl apply -f gateway.yaml
測試部署作業
佈建 Gateway 並準備好兩個 Ray 叢集後,您可以在 JSON 內文中傳送含有不同模型名稱的要求,測試路由功能。
取得閘道 IP 位址:
kubectl get gateways ray-multi-model-gateway在可連上閘道位址的網路中啟動殼層。 您可以在其中一個 Ray 叢集 Pod 上使用 curl:
POD_NAME=$(kubectl get pods -l ray.io/node-type=head -o jsonpath='{.items[0].metadata.name}') kubectl exec -it $POD_NAME -- bash測試將要求傳送至 Gemma 的路徑:
curl http://GATEWAY_IP_ADDRESS/v1/chat/completions \ --header 'Content-Type: application/json' \ --data '{ "model": "gemma-2b-it", "messages": [{"role": "user", "content": "Tell me about GKE."}] }'將
GATEWAY_IP_ADDRESS替換為上一步的 IP 位址。輸出結果會與下列內容相似:
{"id":"chatcmpl-594f7cab-f991-4522-9829-acdbb65d9f67","object":"chat.completion","created":1776379509,"model":"gemma-2b-it","choices":[{"index":0,"message":{"role":"assistant","content":"**Google Kubernetes Engine (GKE)** is a fully managed container orchestration service for Kubernetes [...]測試轉送至 Qwen:
curl http://GATEWAY_IP_ADDRESS/v1/chat/completions \ --header 'Content-Type: application/json' \ --data '{ "model": "qwen-2.5-3b", "messages": [{"role": "user", "content": "How does Ray Serve work?"}] }'輸出結果會與下列內容相似:
{"id":"chatcmpl-dfe3f3b7-45fc-481c-b53e-2fc09c033cdb","object":"chat.completion","created":1776380249,"model":"qwen-2.5-3b","choices":[{"index":0,"message":{"role":"assistant","content":"Ray Serve facilitates the hosting and deployment of scalable microservices. [...]
以主體為準的路由器會自動擷取 model 欄位的值,並確保每項要求都會傳送至 gateway.yaml 檔案中設定的正確後端服務。
清除所用資源
刪除叢集:
gcloud container clusters delete ${CLUSTER}
後續步驟
- 瞭解 Ray Serve 的效能最佳化作業。
- 進一步瞭解 GKE 上的閘道。