このドキュメントでは、Kubernetes Gateway API と GKE Inference Gateway を構成して、Google Kubernetes Engine(GKE)上の複数の Ray Serve クラスタで推論リクエストを管理する方法について説明します。この構成により、複数のチームのトラフィック管理を一元化し、容量を増やすためにワークロードをリージョンに分散し、リクエスト本文の内容に基づいてモデル認識ルーティングを実装できます。
GKE Inference Gateway と Ray Serve を使用するメリット
GKE Inference Gateway と Ray Serve を使用すると、次のメリットがあります。
- パスルーティング: 各 RayService をパス接頭辞で構成し、複数の Ray Service にルーティングする 1 つの Gateway で提供します。
- パス接頭辞ルールの設定の詳細については、Gateway API ドキュメントをご覧ください。
- モデル対応ルーティング: リクエスト本文に基づいてルーティングする RayService を選択します。たとえば、OpenAI-API JSON リクエストからリクエストされたモデルを抽出します。
- ガバナンス: サービスを使用するために API キーを要求するか、認証と API 管理に Apigee を使用してユーザーの割り当てを適用します。
- マルチリージョン: マルチクラスタ Gateway を使用して、RayService で複数の GKE クラスタにトラフィックを分散し、可用性または容量を向上させます。
- 関心の分離: 別々のチームが管理し、別々のロールアウトに従い、異なるトポロジで実行できる���別の RayService を使用します。
- セキュリティ: Gateway を SSL ターミネータとして使用して、インターネット経由のユーザー トラフィックを保護します。詳細については、Gateway のセキュリティをご覧ください。
ルーティングを構成するには、Gateway、HTTPRoute、RayService をデプロイする必要があります。通常、各ターゲット Ray クラスタの Kubernetes Service は KubeRay によって作成されます。Ray Serve は、InferencePool やエンドポイント選択ツールを作成することなく、クラスタ内でリクエスト負荷を分散します。
GKE の Ray Serve のモデル認識ルーティング
モデル認識ルーティングは、本文ベースのルーティング拡張機能によって有効になります。ボディベースのルーティングを使用すると、ユーザーのリクエストで指定されたモデルに基づいてトラフィックを異なる RayService に転送できます。これにより、複数の Ray クラスタでホストされている多くのモデルを処理できる単一のエンドポイントを作成できます。ユーザーはアクセスが簡素化され、アプリ デベロッパーは各 Ray エンドポイントの構成を制御できます。
モデル認識ルーティングを構成するには、次の主要コンポーネントをデプロイします。
- JSON ペイロードからモデル名を抽出する本文ベースのルーター拡張機能。このルーター拡張機能は、Helm を使用してデプロイされます。
- 受信トラフィックを処理する GKE Gateway(L7 リージョン内部アプリケーション ロードバランサ)。
- ルーター拡張機能によって入力されたヘッダーを使用して、トラフィックを正しい Ray Service に転送する HTTPRoute ルール。
- サイロ化されたモデルのライフサイクルと自動スケーリングを管理する複数の 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 アクセス トークンに置き換えます。
インフラストラクチャを準備する
このセクションでは、L4 GPU を使用して Ray 対応、Gateway 対応の GKE クラスタを設定します。
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リージョン内部アプリケーション ロードバランサのプロキシ専用サブネットを作成します。これは、ボディベースのルーティングに必要です。
gcloud compute networks subnets create bbr-proxy-only-subnet \ --purpose=REGIONAL_MANAGED_PROXY \ --role=ACTIVE \ --region=${REGION} \ --network=default \ --range=192.168.10.0/24Hugging 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
Deployment をテストする
Gateway がプロビジョニングされ、両方の Ray クラスタの準備ができたら、JSON 本文で異なるモデル名を使用してリクエストを送信し、ルーティングをテストできます。
Gateway の IP アドレスを取得します。
kubectl get gateways ray-multi-model-gatewayGateway アドレスに到達できるネットワークでシェルを起動します。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 -- bashGemma へのルーティングをテストしてリクエストを送信します。
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 の Gateway の詳細を確認する。