vLLM Kubernetes: Guía Completa de Despliegue

2026.02.09
Technology
438 Words
vLLM Kubernetes: Guía Completa de Despliegue

Parte 2 de 6. En la Parte 1 cubrimos la arquitectura y los prerrequisitos. Aquí desplegamos vLLM en Kubernetes paso a paso. Continúa en Parte 3: Paralelismo de Tensores y Cuantización.

Paso a paso: Ejecutar vLLM en Kubernetes

Estos seis pasos numerados te llevan de un setup de desarrollo con una GPU a un servidor de inferencia multi-GPU completo en Kubernetes.

Paso 1: Seleccionar la imagen de contenedor de vLLM

Siempre ancla a una versión específica. latest no tiene lugar en vLLM production.

Terminal window
docker pull vllm/vllm-openai:v0.8.4

Para despliegues con hardening de seguridad:

FROM vllm/vllm-openai:v0.8.4
USER root
RUN pip install --no-cache-dir transformers==4.48.0 accelerate==1.3.0
USER vllm

Paso 2: Crear el manifiesto de Deployment con recursos GPU

Este despliegue de una sola GPU es adecuado para modelos como Mistral 7B o Llama 3 8B:

vllm-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-inference
namespace: llm-serving
labels:
app: vllm
model: llama-3-8b
spec:
replicas: 1
selector:
matchLabels:
app: vllm
template:
metadata:
labels:
app: vllm
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8000"
prometheus.io/path: "/metrics"
spec:
nodeSelector:
nvidia.com/gpu.present: "true"
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
containers:
- name: vllm
image: vllm/vllm-openai:v0.8.4
command:
- python
- -m
- vllm.entrypoints.openai.api_server
args:
- --model
- meta-llama/Meta-Llama-3-8B-Instruct
- --dtype
- bfloat16
- --max-model-len
- "8192"
- --gpu-memory-utilization
- "0.9"
- --max-num-seqs
- "256"
- --port
- "8000"
ports:
- containerPort: 8000
name: http
resources:
limits:
nvidia.com/gpu: "1"
memory: "48Gi"
cpu: "8"
requests:
nvidia.com/gpu: "1"
memory: "32Gi"
cpu: "4"
env:
- name: HF_HOME
value: "/models"
- name: VLLM_LOGGING_LEVEL
value: "INFO"
volumeMounts:
- name: model-cache
mountPath: /models
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 120
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 60
periodSeconds: 10
volumes:
- name: model-cache
persistentVolumeClaim:
claimName: vllm-model-pvc

Banderas clave explicadas:

BanderaValorPropósito
--dtype bfloat16bfloat16Precisión y memoria balanceadas. Usa float16 para GPUs antiguas sin soporte bf16.
--max-model-len 81928192Límite estricto en la longitud total de secuencia (input + output).
--gpu-memory-utilization 0.90.9Reserva 90% de la VRAM GPU para vLLM. Deja espacio para el scratch space de CUDA.
--max-num-seqs 256256Secuencias concurrentes máximas. Este es tu techo de batch size.

Aplica el manifiesto:

Terminal window
kubectl create namespace llm-serving
kubectl apply -f vllm-deployment.yaml

Paso 3: Configurar multi-GPU con tensor parallelism

Definición de entidad: Tensor parallelism: Una técnica que divide capas individuales de transformers entre múltiples GPUs. Cada GPU procesa un shard de las capas de atención y MLP mientras NCCL all-reduce sincroniza las activaciones.

Cuando tu modelo excede la memoria de una sola GPU, agrega --tensor-parallel-size. Este valor debe coincidir con nvidia.com/gpu en resources.limits:

vllm-deployment-multi-gpu.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-inference-70b
namespace: llm-serving
spec:
replicas: 1
selector:
matchLabels:
app: vllm-70b
template:
metadata:
labels:
app: vllm-70b
spec:
nodeSelector:
node-type: gpu
containers:
- name: vllm
image: vllm/vllm-openai:v0.8.4
command:
- python
- -m
- vllm.entrypoints.openai.api_server
args:
- --model
- meta-llama/Meta-Llama-3-70B-Instruct
- --tensor-parallel-size
- "4"
- --dtype
- bfloat16
- --max-model-len
- "32768"
- --gpu-memory-utilization
- "0.92"
- --max-num-seqs
- "128"
- --port
- "8000"
ports:
- containerPort: 8000
resources:
limits:
nvidia.com/gpu: "4"
memory: "384Gi"
cpu: "32"
requests:
nvidia.com/gpu: "4"
memory: "256Gi"
cpu: "16"
env:
- name: NCCL_IB_DISABLE
value: "1"
- name: HF_HOME
value: "/models"

Crítico: --tensor-parallel-size debe ser exactamente igual a nvidia.com/gpu en resources.limits. Cualquier discrepancia produce errores de inicialización de NCCL que te harán perder horas de debugging.

Paso 4: Montar modelos desde almacenamiento local o HuggingFace

Opción A: HuggingFace Hub (solo desarrollo)

Terminal window
kubectl create secret generic hf-token \
--from-literal=token=$HF_TOKEN -n llm-serving

Opción B: PV local (recomendado para producción)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: vllm-model-pvc
namespace: llm-serving
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 500Gi
storageClassName: fast-local-nvme

Pre-descarga vía un Kubernetes Job:

Terminal window
kubectl apply -f - <<EOF
apiVersion: batch/v1
kind: Job
metadata:
name: model-downloader
namespace: llm-serving
spec:
template:
spec:
containers:
- name: dl
image: vllm/vllm-openai:v0.8.4
command: [huggingface-cli, download, meta-llama/Meta-Llama-3-8B-Instruct, --local-dir, /models/llama-3-8b]
env:
- name: HF_TOKEN
valueFrom:
secretKeyRef:
name: hf-token
key: token
volumeMounts: [{name: cache, mountPath: /models}]
volumes: [{name: cache, persistentVolumeClaim: {claimName: vllm-model-pvc}}]
restartPolicy: OnFailure
EOF

Paso 5: Exponer el servidor de API compatible con OpenAI

apiVersion: v1
kind: Service
metadata:
name: vllm-service
namespace: llm-serving
spec:
selector:
app: vllm
ports:
- port: 8000
targetPort: 8000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: vllm-ingress
namespace: llm-serving
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts: [llm-api.yourdomain.com]
secretName: vllm-tls
rules:
- host: llm-api.yourdomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: vllm-service
port:
number: 8000

Nota: Configura los timeouts de proxy a 3600 segundos. Los timeouts por defecto de NGINX son de 60s, lo que mata requests de LLM de larga duración a mitad de generación.

Prueba la conectividad:

Terminal window
kubectl port-forward svc/vllm-service 8000:8000 -n llm-serving
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "meta-llama/Meta-Llama-3-8B-Instruct", "messages": [{"role": "user", "content": "Hello"}], "max_tokens": 50}'

Paso 6: Configurar Horizontal Pod Autoscaler con métricas personalizadas

HPA basado en CPU no sirve para inferencia de LLM. La utilización de GPU no tiene correlación con las métricas de CPU. Debes escalar en las métricas Prometheus de vLLM.

Instala Prometheus Adapter:

Terminal window
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm upgrade --install prometheus-adapter prometheus-community/prometheus-adapter \
--namespace monitoring --set prometheus.url=http://prometheus.monitoring.svc

Configura una regla de métrica personalizada:

apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-adapter
namespace: monitoring
data:
config.yaml: |
rules:
- seriesQuery: 'vllm_num_requests_running'
resources:
overrides:
namespace: {resource: namespace}
pod: {resource: pod}
metricsQuery: 'avg(vllm_num_requests_running{<<.LabelMatchers>>}) by (<<.GroupBy>>)'

Crea el HPA:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: vllm-hpa
namespace: llm-serving
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: vllm-inference
minReplicas: 1
maxReplicas: 5
metrics:
- type: Pods
pods:
metric:
name: vllm_num_requests_running
target:
type: AverageValue
averageValue: "50"
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies: [{type: Pods, value: 1, periodSeconds: 120}]
scaleDown:
stabilizationWindowSeconds: 300
policies: [{type: Pods, value: 1, periodSeconds: 300}]

Tip de producción: La estabilización de scale-down es de 5 minutos por una buena razón: iniciar en frío un modelo de 70B toma 3–5 minutos. Un scale-down agresivo destruirá tu latencia durante picos de tráfico.

Continúa en Parte 3: Paralelismo de Tensores y Cuantización para la configuración de producción.

# Vllm # Kubernetes # IA # Gpu # Llm # produccion