Implementação de referência de serviço de modelo aberto no Distributed Cloud (somente software)

Visão geral

Este documento serve como guia de Implementação de referência da solução (SRI), descrevendo as etapas concretas necessárias para implantar, disponibilizar e validar a solução Open Model Serving somente em software do Distributed Cloud.

Este guia implementa a implantação do mecanismo de serviço vLLM otimizado executando o Gemma 4 (google/gemma-4-31B-it) em uma configuração de cluster de nó único somente de software do Distributed Cloud voltada para implantação de borda usando recursos físicos de GPU NVIDIA (por exemplo, RTX PRO 6000).

Este tutorial foi projetado para ser executado em um cliente de terminal da CLI com acesso kubectl ao cluster somente de software do Distributed Cloud.

Objetivos

Ao concluir esta implementação de referência da solução, você vai:

  • Configure os parâmetros do ambiente de veiculação usando um arquivo .env local.
  • Implante uma reivindicação de volume permanente (PVC) usando a classe de armazenamento local-shared para manter os pesos do modelo.
  • Implante o mecanismo de exibição do vLLM otimizado usando contêineres qualificados da Vertex AI, mapeando recursos nvidia.com/gpu físicos.
  • Implante a interface da Web do Gradio para fornecer uma interface de chat interativa.
  • Estabeleça túneis de encaminhamento de porta local para validar a capacidade de resposta do serviço usando APIs e a interface da Web.
  • Verifique a integração da observabilidade confirmando a ingestão de registros e métricas (incluindo telemetria da GPU) no Cloud Logging e no Cloud Monitoring.

Antes de começar

Pré-requisitos (configuração do cluster)

Este guia pressupõe que você tenha um cluster do Distributed Cloud somente de software em execução com suporte a GPU configurado. Para instalar o cluster, consulte a documentação oficial do Distributed Cloud somente software para bare metal. A configuração da GPU precisa estar em conformidade com a documentação oficial Google Cloud para Configurar e usar GPUs NVIDIA.

Pré-requisitos da estação de trabalho do cliente

Verifique se o ambiente do terminal local tem as seguintes ferramentas instaladas e configuradas:

  • CLI gcloud:obrigatória para configuração do projeto e consulta de registros. Precisa ser autenticado (gcloud auth login) e configurado para oGoogle Cloud projeto ativo em que o cluster somente de software da Distributed Cloud está registrado.
  • kubectl:necessário para gerenciar recursos do cluster. Precisa ser configurado com o contexto adequado para acessar o cluster de software somente do Distributed Cloud de destino (por exemplo, via gateway de conexão ou acesso direto à rede local).
  • curl:necessário para enviar solicitações de teste ao endpoint de serviço.
  • jq:obrigatório para analisar a saída JSON do endpoint de serviço.

Acesso ao modelo do Hugging Face

Para fazer o download e implantar o modelo Gemma 4, você precisa ter acesso ao repositório do Hugging Face:

  1. Conta do Hugging Face:verifique se você tem uma conta registrada no Hugging Face.
  2. Aceitar a licença do modelo:acesse a página do modelo de TI Gemma 4 31B e concorde com os termos da licença para ter acesso aos pesos do modelo restrito.
  3. Gerar token de acesso:gere um token de acesso do usuário com permissões de leitura nas configurações da sua conta do Hugging Face (Configurações -> Tokens de acesso). Esse token será usado como HF_TOKEN na sua configuração.

Configuração de referência central

Todos os parâmetros de implantação são gerenciados por um arquivo .env central localizado em <local-config-dir>/.env. Verifique se esse arquivo existe e contém seus parâmetros específicos (token do Hugging Face, namespace, nome do modelo etc.).

Exemplo de estrutura .env:

# GDCso Cluster Namespace
NAMESPACE_NAME="your-custom-namespace"

# Hugging Face Token (Required to download gated Gemma models)
HF_TOKEN="your-hf-token-here"

# Model Sizing Parameters
MODEL_NAME="google/gemma-4-31B-it"
SAFE_MODEL_NAME="google-gemma-4-31B-it"

# Hyperparameters
MAX_MODEL_LEN=8192
GPU_MEMORY_UTILIZATION=0.95
MAX_NUM_SEQS=512
MAX_NUM_BATCHED_TOKENS=4096
DTYPE="bfloat16"

# Pod Sizing Requests
CPU_REQUEST="4"
MEMORY_REQUEST="80"

Configurar ambiente e credenciais

Criar namespace e secret do Hugging Face

Antes de fazer a implantação, crie o namespace e o secret do token do Hugging Face:

# Navigate to your project root
cd <local-working-dir>

# Sourced from your local .env file
source <local-config-dir>/.env

# Create namespace
kubectl create namespace ${NAMESPACE_NAME} --dry-run=client -o yaml | kubectl apply -f -

# Create Hugging Face token secret
kubectl create secret generic hf-token-secret \
  --from-literal=token="${HF_TOKEN}" \
  -n "${NAMESPACE_NAME}" --dry-run=client -o yaml | kubectl apply -f -

Implantação do vLLM no Kubernetes

A implantação consiste em três manifestos principais: PVC, Service e Deployment. Esses modelos usam variáveis de ambiente que são substituídas no momento da implantação.

Persistent Volume Claim (PVC)

O PVC garante que os pesos do modelo persistam nas reinicializações do pod, usando a classe de armazenamento local-shared somente do software Distributed Cloud.

Crie um arquivo chamado vllm-pvc.yaml com o conteúdo a seguir:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: model-cache-pvc
  namespace: ${NAMESPACE_NAME}
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-shared
  resources:
    requests:
      storage: 100Gi

Serviço

Expõe o servidor de API vLLM internamente na porta 8000.

Crie um arquivo chamado vllm-service.yaml com o conteúdo a seguir:

apiVersion: v1
kind: Service
metadata:
  name: vllm-service
  namespace: ${NAMESPACE_NAME}
  labels:
    app: vllm
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/path: "/metrics"
    prometheus.io/port: "8000"
spec:
  ports:
    - name: http
      port: 8000
      targetPort: 8000
  selector:
    app: vllm
  type: ClusterIP

Implantação

Executa o contêiner vLLM, monta o volume de cache do modelo e solicita recursos físicos de GPU. Embora 96 GB de VRAM sejam adequados para pesos BF16 não quantizados (~62 GB), esta implementação de referência permite a quantização FP8 do Blackwell (--quantization=fp8, pesos de ~31 GB) para expandir o cache KV para 56,53 GiB (tokens 61,728) e aumentar a capacidade de processamento simultânea.

Crie um arquivo chamado vllm-deployment.yaml com o conteúdo a seguir:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-deployment
  namespace: ${NAMESPACE_NAME}
  labels:
    app: vllm
    ai.gke.io/inference-server: vllm
    ai.gke.io/model: ${SAFE_MODEL_NAME}
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: vllm
  template:
    metadata:
      labels:
        app: vllm
        examples.ai.gke.io/source: user-guide
        ai.gke.io/inference-server: vllm
        ai.gke.io/model: ${SAFE_MODEL_NAME}
    spec:
      runtimeClassName: nvidia
      containers:
        - name: vllm-container
          image: us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:gemma4
          imagePullPolicy: IfNotPresent
          command: ["python3", "-m", "vllm.entrypoints.openai.api_server"]
          args:
            - --model=$(MODEL_ID)
            - --host=0.0.0.0
            - --port=8000
            - --tensor-parallel-size=1
            - --enable-log-requests
            - --max-model-len=${MAX_MODEL_LEN}
            - --gpu-memory-utilization=${GPU_MEMORY_UTILIZATION}
            - --max-num-seqs=${MAX_NUM_SEQS}
            - --max-num-batched-tokens=${MAX_NUM_BATCHED_TOKENS}
            - --dtype=${DTYPE}
            - --trust-remote-code
            - --enable-prefix-caching
            - --enable-chunked-prefill
            - --quantization=fp8
          env:
            - name: MODEL_ID
              value: ${MODEL_NAME}
            - name: HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-token-secret
                  key: token
            - name: LD_LIBRARY_PATH
              value: "/usr/local/nvidia/lib64"
          ports:
            - name: http
              containerPort: 8000
          resources:
            requests:
              cpu: ${CPU_REQUEST}
              memory: "${MEMORY_REQUEST}Gi"
              nvidia.com/gpu: "1"
            limits:
              cpu: ${CPU_REQUEST}
              memory: "${MEMORY_REQUEST}Gi"
              nvidia.com/gpu: "1"
          volumeMounts:
            - mountPath: /root/.cache/huggingface
              name: cache-volume
            - mountPath: /dev/shm
              name: dshm
      volumes:
        - name: cache-volume
          persistentVolumeClaim:
            claimName: model-cache-pvc
        - name: dshm
          emptyDir:
            medium: Memory
            sizeLimit: 16Gi

Implantação da interface do Gradio

A interface do Gradio oferece uma interface da Web interativa para conversar com o modelo. Ele é implantado no cluster e se conecta ao serviço vLLM pela rede interna do Kubernetes.

Implantação do Gradio

Crie um arquivo chamado gradio-deployment.yaml com o conteúdo a seguir:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gradio-deployment
  namespace: ${NAMESPACE_NAME}
  labels:
    app: gradio
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gradio
  template:
    metadata:
      labels:
        app: gradio
    spec:
      containers:
      - name: gradio
        image: us-docker.pkg.dev/google-samples/containers/gke/gradio-app:v1.0.4
        resources:
          requests:
            cpu: "250m"
            memory: "512Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        env:
        - name: CONTEXT_PATH
          value: "/v1/chat/completions"
        - name: HOST
          value: "http://vllm-service:8000"
        - name: MODEL_ID
          value: "${MODEL_NAME}"
        ports:
        - containerPort: 7860

Serviço do Gradio

Crie um arquivo chamado gradio-service.yaml com o conteúdo a seguir:

apiVersion: v1
kind: Service
metadata:
  name: gradio-service
  namespace: ${NAMESPACE_NAME}
spec:
  selector:
    app: gradio
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 7860
  type: ClusterIP

Configuração de observabilidade

Para detalhes sobre como configurar a geração de registros e o monitoramento de aplicativos, consulte o guia oficial Geração de registros e monitoramento de aplicativos.

Monitoramento do vLLM

Para ativar a extração de métricas do vLLM pelo Google Cloud Managed Service para Prometheus (GMP), implante um recurso PodMonitoring direcionado aos pods do vLLM.

Crie um arquivo chamado vllm-pod-monitoring.yaml com o conteúdo a seguir:

apiVersion: monitoring.googleapis.com/v1
kind: PodMonitoring
metadata:
  name: vllm-pod-monitoring
  namespace: ${NAMESPACE_NAME}
spec:
  selector:
    matchLabels:
      app: vllm
  endpoints:
  - port: http
    interval: 30s

Monitoramento da GPU

Para ativar a extração de métricas de GPU do NVIDIA DCGM Exporter pelo Google Cloud Managed Service para Prometheus (GMP), implantamos um recurso PodMonitoring no namespace gpu-operator. Para mais detalhes, consulte Enviar métricas de GPU para o Cloud Monitoring.

Crie um arquivo chamado gpu-pod-monitoring.yaml com o conteúdo a seguir:

apiVersion: monitoring.googleapis.com/v1
kind: PodMonitoring
metadata:
  name: dcgm-gmp
  namespace: gpu-operator
spec:
  selector:
    matchLabels:
      app: nvidia-dcgm-exporter
  endpoints:
  - port: metrics
    interval: 30s

Etapas de execução

Implantar manifestos

Aplique os manifestos ao cluster. Como os arquivos YAML contêm marcadores de posição de variáveis de ambiente, use envsubst para substituir as variáveis do arquivo .env antes de aplicá-las.

  1. Navegue até o diretório de trabalho que contém os arquivos YAML:

    cd <local-working-dir>
    
  2. Extraia as variáveis de ambiente:

    source <local-config-dir>/.env
    
  3. Aplique os manifestos em sequência:

    # Apply core serving manifests
    envsubst < vllm-pvc.yaml | kubectl apply -f -
    envsubst < vllm-service.yaml | kubectl apply -f -
    envsubst < vllm-deployment.yaml | kubectl apply -f -
    
    # Apply observability manifests
    envsubst < vllm-pod-monitoring.yaml | kubectl apply -f -
    kubectl apply -f gpu-pod-monitoring.yaml
    
    # Apply Gradio UI manifests
    envsubst < gradio-deployment.yaml | kubectl apply -f -
    envsubst < gradio-service.yaml | kubectl apply -f -
    

Verificação

Monitorar a sequência de inicialização do pod

Faça o streaming dos registros do contêiner para acompanhar a sequência de inicialização:

# 1. Check pod status (wait until it is Running)
kubectl get pods -n ${NAMESPACE_NAME} -l app=vllm

# 2. Stream logs to verify model loading
kubectl logs -f -l app=vllm -n ${NAMESPACE_NAME}

Aguarde até ver o indicador de serviço ativo pronto nos seus logs:

INFO: Application startup complete.

Estabelecer um túnel de encaminhamento de portas

Para testar o endpoint localmente, encaminhe a porta 8000 do serviço:

kubectl port-forward service/vllm-service 8000:8000 -n ${NAMESPACE_NAME}

Mantenha esse terminal aberto ou execute-o em segundo plano.

Endpoint de veiculação de consultas

Em um terminal separado, teste a capacidade de resposta da API:

1. Lista de modelos de consulta

curl -s http://localhost:8000/v1/models | jq

2. Consultar conclusões de chat

curl -s http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "'"${MODEL_NAME}"'",
    "messages": [
      {"role": "user", "content": "What is AGI in 100 words"}
    ],
    "max_tokens": 150
  }' | jq

Verificar as alocações de GPU e VRAM

Para garantir que o modelo esteja usando o hardware de maneira eficiente e que a ocupação de memória esteja correta, execute uma auditoria de GPU.

Auditar a GPU usando nvidia-smi no pod

Recupere o nome do seu pod vLLM ativo e execute nvidia-smi dentro do contêiner:

# Dynamically get the pod name
export VLLM_POD_NAME=$(kubectl get pods -n ${NAMESPACE_NAME} -l app=vllm -o jsonpath='{.items[0].metadata.name}')

# Run nvidia-smi inside the container
kubectl exec ${VLLM_POD_NAME} -n ${NAMESPACE_NAME} -- nvidia-smi

Saída esperada: o resultado deve informar a utilização da VRAM física correspondente ao parâmetro GPU_MEMORY_UTILIZATION. Por exemplo, em uma estação de trabalho com uma NVIDIA RTX PRO 6000 (aproximadamente 96 GB de VRAM) executando google/gemma-4-31B-it com GPU_MEMORY_UTILIZATION=0.95, você verá aproximadamente 95. 800 MiB alocados para VLLM::EngineCore:

+-----------------------------------------------------------------------------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA RTX PRO 6000 Blac...    On  |   00000000:05:00.0 Off |                    0 |
| N/A   36C    P0             85W /  600W |   95805MiB /  97887MiB |      0%      Default |
+-----------------------------------------+------------------------+----------------------+

Verificar a alocação do cache de chave-valor nos registros

Você também pode verificar os registros de alocação interna do vLLM para verificar o tamanho do cache KV e a simultaneidade de tokens:

kubectl logs ${VLLM_POD_NAME} -n ${NAMESPACE_NAME} | grep -E "Available KV cache|GPU KV cache size"

Saída esperada:

(EngineCore pid=362) INFO 06-18 15:03:43 [gpu_worker.py:456] Available KV cache memory: 56.53 GiB
(EngineCore pid=362) INFO 06-18 15:03:43 [kv_cache_utils.py:1316] GPU KV cache size: 61,728 tokens

Isso confirma que 56,53 GiB de VRAM estão reservados para o cache KV de contexto, permitindo um grande número de tokens simultâneos.

Verificar a implantação da interface do Gradio

Quando o pod do Gradio estiver em execução, você poderá acessar a UI estabelecendo um túnel de encaminhamento de porta.

Monitorar o status do pod do Gradio

Verifique se o pod do Gradio está em execução:

kubectl get pods -n ${NAMESPACE_NAME} -l app=gradio

Saída esperada:

NAME                                READY   STATUS    RESTARTS   AGE
gradio-deployment-yyyyyyyy-yyyyy    1/1     Running   0          1m

Estabelecer um túnel de encaminhamento de portas para o Gradio

Encaminhe a porta 8080 do serviço Gradio para a porta 7860 local:

kubectl port-forward service/gradio-service 7860:8080 -n ${NAMESPACE_NAME}

Mantenha esse terminal aberto ou execute-o em segundo plano:

kubectl port-forward service/gradio-service 7860:8080 -n ${NAMESPACE_NAME} > pf_gradio.log 2>&1 & sleep 3

Acessar a UI da Web

  • Se estiver executando em uma estação de trabalho local:abra o navegador e acesse diretamente: http://localhost:7860
  • Se estiver executando no Cloud Shell:use o botão Visualização na Web, selecione Alterar porta, insira 7860 e clique em Alterar e visualizar.

A interface do chatbot do Gradio vai aparecer. Você pode digitar uma mensagem para interagir com o modelo Gemma. O pod do Gradio vai encaminhar a solicitação internamente para o endpoint vllm-service.

Limpar túneis

Para interromper o túnel de encaminhamento de porta:

pkill -f "port-forward service/gradio-service"

Verificação do monitoramento

Depois que o vLLM for implantado e o recurso PodMonitoring for aplicado, você poderá verificar se as métricas estão sendo ingeridas no Cloud Monitoring.

Verificar o status do PodMonitoring

Verifique se o recurso PodMonitoring foi criado e está ativo:

kubectl get podmonitoring -n ${NAMESPACE_NAME}

Verificar a ingestão de métricas usando o console do Google Cloud

Para verificar se as métricas estão sendo ingeridas, use o console do Google Cloud (Metrics Explorer):

  1. Abra o Metrics Explorer no console Google Cloud :
    • Acesse https://console.cloud.google.com/monitoring/metrics-explorer (verifique se você selecionou seu projeto ${GCP_PROJECT_ID}).
  2. No menu suspenso Selecionar uma métrica, procure e selecione:
    • prometheus.googleapis.com/vllm:num_requests_running/gauge para verificar métricas do vLLM.
    • prometheus.googleapis.com/DCGM_FI_DEV_GPU_UTIL/gauge para verificar as métricas de utilização da GPU.
  3. Observe o gráfico para confirmar se os pontos de dados estão sendo representados ativamente.

Verificação de geração de registros

Depois que a carga de trabalho estiver em execução, verifique se os registros estão sendo exportados para o Cloud Logging.

Verificar a ingestão de registros do vLLM

Verifique se os registros do contêiner vLLM estão sendo exportados para o Cloud Logging:

project_id=$(gcloud config get-value project)

gcloud logging read "resource.type=\"k8s_container\" AND resource.labels.namespace_name=\"${NAMESPACE_NAME}\" AND resource.labels.container_name=\"vllm-container\"" --limit=10 --project=${project_id}

Verificar a ingestão de registros do exportador de GPU

Verifique se os registros do contêiner do exportador de GPU estão sendo exportados para o Cloud Logging:

project_id=$(gcloud config get-value project)

gcloud logging read "resource.type=\"k8s_container\" AND resource.labels.namespace_name=\"gpu-operator\" AND resource.labels.container_name=\"nvidia-dcgm-exporter\"" --limit=10 --project=${project_id}

Verificar registros usando o console do Google Cloud (Análise de registros)

Também é possível verificar a ingestão de registros usando o console do Google Cloud :

  1. Abra a Análise de registros no console Google Cloud :
    • Acesse https://console.cloud.google.com/logs/query (verifique se você selecionou seu projeto ${GCP_PROJECT_ID}).
  2. Na caixa Consulta, insira a seguinte consulta para ver os registros do vLLM:

    resource.type="k8s_container"
    resource.labels.namespace_name="<NAMESPACE_NAME>"
    resource.labels.container_name="vllm-container"
    

    (substitua <NAMESPACE_NAME> pelo namespace real, por exemplo, your-custom-namespace).

  3. Clique em Executar consulta. Você vai encontrar as entradas de registro do contêiner vLLM.

  4. Para verificar os registros do exportador de GPU, execute a seguinte consulta:

    resource.type="k8s_container"
    resource.labels.namespace_name="gpu-operator"
    resource.labels.container_name="nvidia-dcgm-exporter"