In diesem Dokument wird beschrieben, wie Sie Inferenzanfragen in mehreren Ray Serve-Clustern in Google Kubernetes Engine (GKE) verwalten, indem Sie die Kubernetes Gateway API und das GKE Inference Gateway konfigurieren. Mit dieser Konfiguration können Sie die Traffic-Verwaltung für mehrere Teams zentralisieren, Arbeitslasten zur Erhöhung der Kapazität auf Regionen verteilen und modellbewusstes Routing basierend auf dem Inhalt des Anfrage-Bodys implementieren.
Vorteile der Verwendung von GKE Inference Gateway und Ray Serve
Die Verwendung von GKE Inference Gateway und Ray Serve bietet folgende Vorteile:
- Pfad-Routing: Konfigurieren Sie jeden RayService mit einem Pfadpräfix und stellen Sie sie dann mit einem Gateway bereit, das zu mehreren Ray-Diensten weiterleitet.
- Weitere Informationen zum Einrichten von Regeln für Pfadpräfixe finden Sie in der Gateway API-Dokumentation.
- Modellbasiertes Routing: Wählen Sie einen RayService aus, an den weitergeleitet werden soll, basierend auf dem Anfragetext. Sie können beispielsweise das angeforderte Modell aus einer JSON-Anfrage der OpenAI API extrahieren.
- Governance: Sie können API-Schlüssel für die Nutzung Ihres Dienstes erforderlich machen oder Kontingente für Nutzer mit Apigee für Authentifizierung und API-Verwaltung erzwingen.
- Mehrere Regionen: Teilen Sie den Traffic mit Multi-Cluster-Gateways auf mehrere GKE-Cluster mit RayServices auf, um eine höhere Verfügbarkeit oder Kapazität zu erzielen.
- Trennung von Belangen: Verwenden Sie separate RayServices, die von separaten Teams verwaltet werden können, separate Rollouts durchlaufen und in verschiedenen Topologien ausgeführt werden.
- Sicherheit: Verwenden Sie Gateway als SSL-Terminator, um den Nutzer-Traffic im Internet zu schützen. Weitere Informationen finden Sie unter Gateway-Sicherheit.
Um das Routing zu konfigurieren, müssen Sie ein Gateway, eine HTTPRoute und einen RayService bereitstellen. Ein Kubernetes-Dienst für jeden Ziel-Ray-Cluster wird in der Regel von KubeRay erstellt. Ray Serve verteilt die Anfragelast im Cluster, ohne dass ein InferencePool oder Endpoint Picker erstellt werden muss.
Modellbezogenes Routing für Ray Serve in GKE
Modellbasiertes Routing wird durch eine Erweiterung für textkörperbasiertes Routing ermöglicht. Mit dem Body-basierten Routing können Sie Traffic nur basierend auf dem in der Nutzeranfrage genannten Modell an verschiedene RayServices weiterleiten. So können Sie einen einzelnen Endpunkt verwenden, über den viele Modelle bereitgestellt werden können, die in mehreren Ray-Clustern gehostet werden. Ihre Nutzer haben einen vereinfachten Zugriff und Ihre App-Entwickler können jeden Ray-Endpunkt konfigurieren.
Um modellbasiertes Routing zu konfigurieren, stellen Sie die folgenden Schlüsselkomponenten bereit:
- Eine Body-basierte Router-Erweiterung zum Extrahieren von Modellnamen aus JSON-Nutzlasten. Diese Router-Erweiterung wird mit Helm bereitgestellt.
- Ein GKE Gateway (regionaler interner Application Load Balancer auf Layer 7) zur Verarbeitung des eingehenden Traffics.
- HTTPRoute-Regeln, um Traffic mithilfe von Headern, die von der Router-Erweiterung ausgefüllt werden, an den richtigen Ray-Dienst weiterzuleiten.
- Mehrere Ray Serve-Cluster zum Verwalten des Lebenszyklus und des Autoscalings von isolierten Modellen.
Hinweis
Führen Sie die folgenden Aufgaben aus, bevor Sie beginnen:
- Aktivieren Sie die Google Kubernetes Engine API. Google Kubernetes Engine API aktivieren
- Wenn Sie die Google Cloud CLI für diese Aufgabe verwenden möchten, müssen Sie die gcloud CLI installieren und dann initialisieren. Wenn Sie die gcloud CLI bereits installiert haben, rufen Sie die neueste Version mit dem Befehl
gcloud components updateab. In früheren gcloud CLI-Versionen werden die Befehle in diesem Dokument möglicherweise nicht unterstützt.
- Prüfen Sie, ob Helm installiert ist.
- Erstellen Sie ein Hugging Face-Konto, falls Sie noch keines haben.
- Sie benötigen ein Hugging Face-Token.
Umgebung vorbereiten
Richten Sie Umgebungsvariablen ein:
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
Ersetzen Sie YOUR_HUGGING_FACE_TOKEN durch Ihr Hugging Face-Zugriffstoken.
Infrastruktur vorbereiten
In diesem Abschnitt richten Sie einen Ray-fähigen, Gateway-fähigen GKE-Cluster mit L4-GPUs ein.
Erstellen Sie einen Cluster mit aktiviertem Ray-Operator und aktivierter 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-4Erstellen Sie einen GPU-Knotenpool für die Arbeitslasten Ihres Modells:
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=4Erstellen Sie ein Nur-Proxy-Subnetz für den regionalen internen Application Load Balancer, das für Body-basiertes Routing erforderlich ist:
gcloud compute networks subnets create bbr-proxy-only-subnet \ --purpose=REGIONAL_MANAGED_PROXY \ --role=ACTIVE \ --region=${REGION} \ --network=default \ --range=192.168.10.0/24So stellen Sie Ihren geheimen Hugging Face-Schlüssel bereit:
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HUGGING_FACE_TOKEN}
Textkörperbasierten Router für modellbasiertes Routing bereitstellen
Die Body-basierte Router-Erweiterung fängt Anfragen ab, parst den JSON-Text und extrahiert das Modellfeld in einen X-Gateway-Model-Name-Header.
Erstellen Sie eine Datei mit dem Namen
helm-values.yamlund dem folgendem Inhalt:bbr: plugins: - type: "body-field-to-header" name: "openai-model-extractor" json: field_name: "model" header_name: "X-Gateway-Model-Name"Installieren Sie den textkörperbasierten Router mit 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
RayServices bereitstellen
Um Ihre Modelle bereitzustellen, müssen Sie die RayService-Manifeste anwenden. Jedes Manifest definiert einen Ray-Cluster, in dem ein bestimmtes LLM ausgeführt wird.
Erstellen Sie eine Datei mit dem Namen
gemma-2b-it.yamlund dem folgendem Inhalt: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-l4Erstellen Sie eine Datei mit dem Namen
qwen2.5-3b.yamlund dem folgendem Inhalt: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-l4Modelle bereitstellen:
kubectl apply -f gemma-2b-it.yaml kubectl apply -f qwen2.5-3b.yaml
Systemdiagnosen konfigurieren
Damit der Load-Balancer den Zustand von Ray-Workern genau überwachen kann, müssen Sie die HealthCheckPolicy-Ressource anwenden.
Erstellen Sie eine Datei mit dem Namen
healthcheck-policy.yamlund dem folgendem Inhalt: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-svcWenden Sie die Richtlinie für Systemdiagnosen an:
kubectl apply -f healthcheck-policy.yaml
Routing konfigurieren
Zum Konfigurieren des Routings müssen Sie die Manifeste Gateway und HTTPRoute anwenden.
Die HTTPRoute enthält Regeln, die mit dem X-Gateway-Model-Name-Header (der vom Body-basierten Router ausgefüllt wird) übereinstimmen, um Traffic an den entsprechenden Ray-Dienst weiterzuleiten.
Erstellen Sie eine Datei mit dem Namen
gateway.yamlund dem folgendem Inhalt: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: 8000Wenden Sie das Gateway und die Route an:
kubectl apply -f gateway.yaml
Deployment testen
Nachdem das Gateway bereitgestellt wurde und beide Ray-Cluster bereit sind, können Sie das Routing testen, indem Sie Anfragen mit verschiedenen Modellnamen im JSON-Textkörper senden.
Rufen Sie die IP-Adresse des Gateways ab:
kubectl get gateways ray-multi-model-gatewayStarten Sie eine Shell in einem Netzwerk, das die Gateway-Adresse erreichen kann. Sie können „curl“ in einem der Ray-Cluster-Pods verwenden:
POD_NAME=$(kubectl get pods -l ray.io/node-type=head -o jsonpath='{.items[0].metadata.name}') kubectl exec -it $POD_NAME -- bashSenden Sie Anfragen, indem Sie das Routing zu Gemma testen:
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."}] }'Ersetzen Sie
GATEWAY_IP_ADDRESSdurch die IP-Adresse aus dem vorherigen Schritt.Die Ausgabe sieht etwa so aus:
{"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 [...]Routing zu Qwen testen:
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?"}] }'Die Ausgabe sieht etwa so aus:
{"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. [...]
Der Body-basierte Router extrahiert automatisch den Wert des Felds model und sorgt dafür, dass jede Anfrage den richtigen Back-End-Dienst erreicht, der in der Datei gateway.yaml konfiguriert ist.
Bereinigen
Löschen Sie den Cluster:
gcloud container clusters delete ${CLUSTER}