Este documento explica como gerenciar solicitações de inferência em vários clusters do Ray Serve no Google Kubernetes Engine (GKE) configurando a API Gateway do Kubernetes e o GKE Inference Gateway. Essa configuração permite centralizar o gerenciamento de tráfego para várias equipes, distribuir cargas de trabalho entre regiões para maior capacidade e implementar o roteamento com reconhecimento de modelo com base no conteúdo do corpo da solicitação.
Benefícios de usar o GKE Inference Gateway e o Ray Serve
O uso do GKE Inference Gateway e do Ray Serve oferece os seguintes benefícios:
- Roteamento de caminho: configure cada RayService com um prefixo de caminho e, em seguida, disponibilize
os com um roteamento de gateway para vários serviços do Ray.
- Para mais informações sobre como configurar regras de prefixo de caminho, consulte a documentação da API Gateway.
- Roteamento com reconhecimento de modelo: escolha um RayService para rotear com base no corpo da solicitação. Por exemplo, extraindo o modelo solicitado de uma solicitação JSON da API OpenAI.
- Governança: exija chaves de API para usar seu serviço ou aplique cotas para usuários usando a Apigee para autenticação e gerenciamento de API.
- Várias regiões: divida o tráfego em vários clusters do GKE com RayServices para alcançar maior disponibilidade ou capacidade com gateways de vários clusters.
- Separação de interesses: use RayServices separados, que podem ser administrados por equipes separadas, seguir implementações separadas e ser executados em topologias diferentes.
- Segurança: use o gateway para atuar como o terminador SSL para ajudar a proteger o tráfego de usuários na Internet. Para mais informações, consulte Segurança do gateway.
Para configurar o roteamento, implante um gateway, HTTPRoute e RayService. Um serviço do Kubernetes para cada cluster do Ray de destino é normalmente criado pelo KubeRay. O Ray Serve distribui a carga de solicitações no cluster, sem a necessidade de criar um InferencePool ou um seletor de endpoints.
Roteamento com reconhecimento de modelo para Ray Serve no GKE
O roteamento com reconhecimento de modelo é ativado por uma extensão de roteamento baseada no corpo. O roteamento baseado no corpo permite direcionar o tráfego para diferentes RayServices com base apenas no modelo nomeado na solicitação do usuário, o que permite ter um único endpoint que pode disponibilizar muitos modelos hospedados em vários clusters do Ray. Seus usuários têm acesso simplificado, e os desenvolvedores de apps têm controle sobre a configuração de cada endpoint do Ray.
Para configurar o roteamento com reconhecimento de modelo, implante os seguintes componentes principais:
- Uma extensão de roteador baseada no corpo para extrair nomes de modelos de payloads JSON. Essa extensão de roteador é implantada usando o Helm.
- Um gateway do GKE (balanceador de carga de aplicativo interno regional de camada 7) para processar o tráfego de entrada.
- Regras HTTPRoute para direcionar o tráfego ao serviço do Ray correto usando cabeçalhos preenchidos pela extensão do roteador.
- Vários clusters do Ray Serve para gerenciar o ciclo de vida e o escalonamento automático de modelos isolados.
Antes de começar
Antes de começar, verifique se você realizou as tarefas a seguir:
- Ativar a API Google Kubernetes Engine. Ativar a API Google Kubernetes Engine
- Se você quiser usar a Google Cloud CLI para essa tarefa,
instale e, em seguida,
inicialize a
CLI gcloud. Se você instalou a CLI gcloud anteriormente, instale a versão mais recente executando o comando
gcloud components update. Talvez as versões anteriores da CLI gcloud não sejam compatíveis com a execução dos comandos neste documento.
- Verifique se o Helm está instalado.
- Crie uma conta do Hugging Face, se ainda não tiver uma.
- Verifique se você tem um token do Hugging Face.
Preparar o ambiente
Configure as variáveis de ambiente:
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
Substitua YOUR_HUGGING_FACE_TOKEN pelo seu token de acesso do Hugging Face.
Preparar sua infraestrutura
Nesta seção, você configura um cluster do GKE ativado para o Ray e o gateway com GPUs L4.
Crie um cluster com o operador Ray e a API Gateway ativados:
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-4Crie um pool de nós de GPU para as cargas de trabalho do modelo:
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=4Crie uma sub-rede somente proxy para o balanceador de carga de aplicativo interno regional, que é exigido pelo roteamento baseado no corpo:
gcloud compute networks subnets create bbr-proxy-only-subnet \ --purpose=REGIONAL_MANAGED_PROXY \ --role=ACTIVE \ --region=${REGION} \ --network=default \ --range=192.168.10.0/24Implante seu secret do Hugging Face:
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HUGGING_FACE_TOKEN}
Implantar o roteador baseado no corpo para roteamento com reconhecimento de modelo
A extensão do roteador baseado no corpo intercepta solicitações, analisa o corpo JSON e extrai o campo do modelo em um cabeçalho X-Gateway-Model-Name.
Crie um arquivo chamado
helm-values.yamlcom o conteúdo a seguir:bbr: plugins: - type: "body-field-to-header" name: "openai-model-extractor" json: field_name: "model" header_name: "X-Gateway-Model-Name"Instale o roteador baseado no corpo usando o 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
Implantar RayServices
Para implantar seus modelos, aplique os manifestos RayService. Cada manifesto define um cluster do Ray que executa um LLM específico.
Crie um arquivo chamado
gemma-2b-it.yamlcom o conteúdo a seguir: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-l4Crie um arquivo chamado
qwen2.5-3b.yamlcom o conteúdo a seguir: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-l4Implante os modelos:
kubectl apply -f gemma-2b-it.yaml kubectl apply -f qwen2.5-3b.yaml
Configurar verificações de integridade
Para garantir que o balanceador de carga monitore com precisão a integridade do worker do Ray, aplique o recurso HealthCheckPolicy.
Crie um arquivo chamado
healthcheck-policy.yamlcom o conteúdo a seguir: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-svcAplique a política de verificação de integridade:
kubectl apply -f healthcheck-policy.yaml
Configurar o roteamento
Para configurar o roteamento, aplique os manifestos Gateway e HTTPRoute.
O HTTPRoute contém regras que correspondem ao cabeçalho X-Gateway-Model-Name (preenchido pelo roteador baseado no corpo) para rotear o tráfego para o serviço do Ray apropriado.
Crie um arquivo chamado
gateway.yamlcom o conteúdo a seguir: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: 8000Aplique o gateway e a rota:
kubectl apply -f gateway.yaml
Teste a implantação
Depois que o gateway for provisionado e os dois clusters do Ray estiverem prontos, você poderá testar o roteamento enviando solicitações com nomes de modelos diferentes no corpo JSON.
Acessar o endereço IP do gateway:
kubectl get gateways ray-multi-model-gatewayInicie um shell em uma rede que possa acessar o endereço do gateway. Você pode usar o curl em um dos pods do cluster do Ray:
POD_NAME=$(kubectl get pods -l ray.io/node-type=head -o jsonpath='{.items[0].metadata.name}') kubectl exec -it $POD_NAME -- bashEnvie solicitações testando o roteamento para 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."}] }'Substitua
GATEWAY_IP_ADDRESSpelo endereço IP da etapa anterior.O resultado será assim:
{"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 [...]Teste o roteamento para 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?"}] }'O resultado será assim:
{"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. [...]
O roteador baseado no corpo extrai automaticamente o valor do campo model e garante que cada solicitação chegue ao serviço de back-end correto configurado no arquivo gateway.yaml.
Limpar
Exclua o cluster:
gcloud container clusters delete ${CLUSTER}
A seguir
- Saiba mais sobre as otimizações de desempenho do Ray Serve.
- Leia mais sobre o gateway no GKE.