Publicación de modelos abiertos en la implementación de referencia de solo software de Distributed Cloud

Descripción general

Este documento sirve como guía de la Implementación de referencia de la solución (SRI) y describe los pasos concretos necesarios para implementar, entregar y validar la solución de Open Model Serving en el software de Distributed Cloud únicamente.

En esta guía, se implementa la implementación del motor de servicio vLLM optimizado que ejecuta Gemma 4 (google/gemma-4-31B-it) en una configuración de clúster de un solo nodo solo de software de Distributed Cloud diseñada para la implementación en el borde que utiliza recursos de GPU de NVIDIA físicos (p.ej., RTX PRO 6000).

Este recorrido está diseñado para ejecutarse desde un cliente de terminal de la CLI con acceso de kubectl al clúster solo de software de Distributed Cloud.

Objetivos

Cuando completes esta implementación de referencia de la solución, podrás hacer lo siguiente:

  • Configura los parámetros del entorno de entrega a través de un archivo .env local.
  • Implementa un reclamo de volumen persistente (PVC) con la clase de almacenamiento local-shared para conservar las ponderaciones del modelo.
  • Implementa el motor de entrega de vLLM optimizado con contenedores calificados para Vertex AI, que asignan recursos físicos de nvidia.com/gpu.
  • Implementa la IU web de Gradio para proporcionar una interfaz de chat interactiva.
  • Establece túneles de reenvío de puertos locales para validar la capacidad de respuesta de la publicación a través de las APIs y la IU web.
  • Verifica la integración de la observabilidad. Para ello, confirma la transferencia de registros y métricas (incluidos los datos de telemetría de la GPU) a Cloud Logging y Cloud Monitoring.

Antes de comenzar

Requisitos previos (configuración del clúster)

En esta guía, se supone que tienes un clúster de Distributed Cloud solo de software en ejecución con la compatibilidad con GPU configurada. Para instalar el clúster, consulta la documentación oficial de Distributed Cloud (solo software) para Bare Metal. La configuración de la GPU debe cumplir con la documentación oficial de Google Cloud Cómo configurar y usar GPUs de NVIDIA.

Requisitos previos de la estación de trabajo del cliente

Asegúrate de que tu entorno de terminal local tenga instaladas y configuradas las siguientes herramientas:

  • CLI de gcloud: Se requiere para configurar el proyecto y consultar los registros. Debe estar autenticado (gcloud auth login) y configurado en el proyectoGoogle Cloud activo en el que se registra el clúster solo de software de Distributed Cloud.
  • kubectl: Se requiere para administrar los recursos del clúster. Se debe configurar con el contexto adecuado para acceder al clúster de software de Distributed Cloud de destino (p.ej., a través de la puerta de enlace de conexión o el acceso directo a la red local).
  • curl: Se requiere para enviar solicitudes de prueba al extremo de servicio.
  • jq: Se requiere para analizar el resultado JSON del extremo de servicio.

Acceso al modelo de Hugging Face

Para descargar e implementar el modelo Gemma 4, debes tener acceso al repositorio de Hugging Face:

  1. Cuenta de Hugging Face: Asegúrate de tener una cuenta registrada en Hugging Face.
  2. Acepta la licencia del modelo: Navega a la página del modelo Gemma 4 31B IT y acepta las condiciones de la licencia para obtener acceso a los pesos del modelo restringido.
  3. Genera un token de acceso: Genera un token de acceso de usuario con permisos de lectura en la configuración de tu cuenta de Hugging Face (Configuración -> Tokens de acceso). Este token se usará como HF_TOKEN en tu configuración.

Configuración de referencia central

Todos los parámetros de implementación se administran a través de un archivo .env central ubicado en <local-config-dir>/.env. Asegúrate de que este archivo exista y contenga tus parámetros específicos (token de Hugging Face, espacio de nombres, nombre del modelo, etcétera).

Ejemplo de estructura .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"

Configura el entorno y las credenciales

Crea el espacio de nombres y el secreto de Hugging Face

Antes de implementar, debes crear el espacio de nombres y el secreto del token de 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 -

Implementación de vLLM en Kubernetes

La implementación consta de tres manifiestos principales: PVC, Service y Deployment. Estas plantillas usan variables de entorno que se sustituyen en el momento de la implementación.

Persistent Volume Claim (PVC)

La PVC garantiza que los pesos del modelo persistan en los reinicios del pod, ya que usa la clase de almacenamiento local-shared solo para el software de Distributed Cloud.

Crea un archivo llamado vllm-pvc.yaml con el siguiente contenido:

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

Servicio

Expone el servidor de la API de vLLM de forma interna en el puerto 8000.

Crea un archivo llamado vllm-service.yaml con el siguiente contenido:

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

Implementación

Ejecuta el contenedor de vLLM, activa el volumen de caché del modelo y solicita recursos de GPU físicos. Si bien 96 GB de VRAM se ajustan a los pesos de BF16 sin cuantificar (alrededor de 62 GB), esta implementación de referencia permite la cuantificación de FP8 de Blackwell (--quantization=fp8, alrededor de 31 GB de pesos) para expandir la caché de KV a 56.53 GiB (61,728 tokens) para una mayor capacidad de procesamiento simultánea.

Crea un archivo llamado vllm-deployment.yaml con el siguiente contenido:

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

Implementación de la IU de Gradio

La IU de Gradio proporciona una interfaz web interactiva para chatear con el modelo. Se implementa dentro del clúster y se conecta al servicio de vLLM a través de la red interna de Kubernetes.

Implementación de Gradio

Crea un archivo llamado gradio-deployment.yaml con el siguiente contenido:

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

Servicio de Gradio

Crea un archivo llamado gradio-service.yaml con el siguiente contenido:

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

Configuración de observabilidad

Para obtener detalles sobre la configuración del registro y la supervisión de aplicaciones, consulta la guía oficial de Registro y supervisión de aplicaciones.

Supervisión de vLLM

Para habilitar la recopilación de métricas de vLLM por parte de Google Cloud Managed Service para Prometheus (GMP), implementamos un recurso PodMonitoring que segmenta los Pods de vLLM.

Crea un archivo llamado vllm-pod-monitoring.yaml con el siguiente contenido:

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

Supervisión de la GPU

Para habilitar la recopilación de métricas de GPU del exportador de NVIDIA DCGM por parte de Google Cloud Managed Service para Prometheus (GMP), implementamos un recurso PodMonitoring en el espacio de nombres gpu-operator. Para obtener más detalles, consulta Envía métricas de GPU a Cloud Monitoring.

Crea un archivo llamado gpu-pod-monitoring.yaml con el siguiente contenido:

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

Pasos de ejecución

Implementa manifiestos

Aplica los manifiestos al clúster. Dado que los archivos YAML contienen marcadores de posición de variables de entorno, usa envsubst para sustituir las variables de tu archivo .env antes de aplicarlas.

  1. Navega a tu directorio de trabajo que contiene los archivos YAML:

    cd <local-working-dir>
    
  2. Obtén las variables de entorno:

    source <local-config-dir>/.env
    
  3. Aplica los manifiestos en secuencia:

    # 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 -
    

Verificación

Secuencia de inicio del Pod de supervisión

Transmite los registros del contenedor para hacer un seguimiento de la secuencia de inicio:

# 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}

Espera hasta que veas la señal de publicación activa en tus registros:

INFO: Application startup complete.

Establece un túnel de redirección de puertos

Para probar el extremo de forma local, reenvía el puerto de servicio 8000:

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

Mantén esta terminal abierta o ejecútala en segundo plano.

Extremo de servicio de consultas

Desde otra terminal, prueba la capacidad de respuesta de la API:

1. Lista de modelos de consultas

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

2. Consultar finalizaciones 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

Verifica las asignaciones de GPU y VRAM

Para asegurarte de que el modelo utilice el hardware de manera eficiente y de que el espacio de memoria sea correcto, puedes ejecutar una auditoría de GPU.

Audita la GPU con nvidia-smi dentro del Pod

Recupera el nombre de tu Pod de vLLM activo y ejecuta nvidia-smi dentro del contenedor:

# 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

Resultado esperado: El resultado debe informar la utilización de la VRAM física que coincide con tu parámetro GPU_MEMORY_UTILIZATION. Por ejemplo, en una estación de trabajo con una NVIDIA RTX PRO 6000 (aprox. 96 GB de VRAM) que ejecuta google/gemma-4-31B-it con GPU_MEMORY_UTILIZATION=0.95, deberías ver ~95,800 MiB asignados a 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 |
+-----------------------------------------+------------------------+----------------------+

Verifica la asignación de la caché de KV en los registros

También puedes consultar los registros de asignación internos de vLLM para verificar el tamaño de la caché de KV y la simultaneidad de tokens:

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

Resultado esperado:

(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

Esto confirma que se reservaron 56.53 GiB de VRAM para la caché de KV de contexto, lo que permite una gran cantidad de tokens simultáneos.

Verifica la implementación de la IU de Gradio

Una vez que el pod de Gradio esté en ejecución, puedes acceder a la IU estableciendo un túnel de reenvío de puertos.

Supervisa el estado del pod de Gradio

Asegúrate de que el Pod de Gradio esté en ejecución:

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

Resultado esperado:

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

Establece un túnel de redirección de puertos a Gradio

Reenvía el puerto 8080 del servicio de Gradio a tu puerto local 7860:

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

Mantén esta terminal abierta o ejecútala en segundo plano:

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

Accede a la IU web

  • Si se ejecuta en una estación de trabajo local: Abre tu navegador y navega directamente a: http://localhost:7860
  • Si se ejecuta dentro de Cloud Shell: Usa el botón Vista previa en la Web, selecciona Cambiar puerto, ingresa 7860 y haz clic en Cambiar y obtener vista previa.

Deberías ver la interfaz del chatbot de Gradio. Puedes escribir un mensaje para interactuar con el modelo de Gemma. El pod de Gradio enrutará la solicitud de forma interna al extremo vllm-service.

Limpia los túneles

Para detener el túnel de redirección de puertos, haz lo siguiente:

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

Verificación de la supervisión

Una vez que se implementa vLLM y se aplica el recurso PodMonitoring, puedes verificar que las métricas se transfieran a Cloud Monitoring.

Verifica el estado de PodMonitoring

Asegúrate de que el recurso PodMonitoring esté creado y activo:

kubectl get podmonitoring -n ${NAMESPACE_NAME}

Verifica la transferencia de métricas con la consola de Google Cloud

Puedes verificar que las métricas se estén transfiriendo a través de la Google Cloud consola (Explorador de métricas):

  1. Abre el Explorador de métricas en la consola de Google Cloud :
    • Ve a https://console.cloud.google.com/monitoring/metrics-explorer (asegúrate de seleccionar tu proyecto ${GCP_PROJECT_ID}).
  2. En el menú desplegable Seleccionar una métrica, busca y selecciona lo siguiente:
    • prometheus.googleapis.com/vllm:num_requests_running/gauge para verificar las métricas de vLLM.
    • prometheus.googleapis.com/DCGM_FI_DEV_GPU_UTIL/gauge para verificar las métricas de utilización de la GPU.
  3. Observa el gráfico para confirmar que los puntos de datos se estén trazando de forma activa.

Verificación de registros

Una vez que se ejecute la carga de trabajo, puedes verificar que los registros se exporten a Cloud Logging.

Verifica la transferencia de registros de vLLM

Verifica que los registros del contenedor de vLLM se exporten a 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}

Verifica la transferencia de registros del exportador de GPU

Verifica que los registros del contenedor del exportador de GPU se exporten a 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}

Verifica los registros con la consola Google Cloud (Explorador de registros)

También puedes verificar la transferencia de registros con la consola Google Cloud :

  1. Abre el Explorador de registros en la consola de Google Cloud :
    • Ve a https://console.cloud.google.com/logs/query (asegúrate de seleccionar tu proyecto ${GCP_PROJECT_ID}).
  2. En el cuadro Consulta, ingresa la siguiente consulta para ver los registros de vLLM:

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

    (reemplaza <NAMESPACE_NAME> por tu espacio de nombres real, p.ej., your-custom-namespace).

  3. Haz clic en Ejecutar consulta. Deberías ver las entradas de registro del contenedor de vLLM.

  4. Para verificar los registros del exportador de GPU, ejecuta la siguiente consulta:

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