Phase 17 - Lesson 03

Autoscaling de GPU en Kubernetes — Karpenter, KAI Scheduler, Gang Scheduling

Tres capas, no una. Karpenter aprovisiona nodos dinámicamente (menos de un minuto, 40% más rápido que Cluster Autoscaler). KAI Scheduler maneja gang scheduling, reconocimiento de topología (topology awareness) y colas jerárquicas; evita la trampa de asignación parcial "7 de 8", donde siete nodos esperan y consumen recursos ociosos por una GPU faltante. Los autoscalers a nivel de aplicación (NVIDIA Dynamo Planner, llm-d Workload Variant Autoscaler) escalan según señales específicas de inferencia (profundidad de cola, utilización de KV cache), no en el ciclo de trabajo de CPU/DCGM. La trampa clásica de HPA es que DCGM_FI_DEV_GPU_UTIL es una medición de ciclo de trabajo: 100% de utilización podría ser 10 solicitudes o 100. vLLM preasigna memoria de KV cache, por lo que la memoria nunca activa la reducción de escala (scale-down). Esta lección te enseña a componer las tres capas y evitar la política predeterminada de Karpenter WhenEmptyOrUnderutilized que finaliza trabajos de GPU en ejecución a mitad de la inferencia.

Tipo: Aprender Lenguajes: Python (stdlib, simulador simplificado de autoscaler por profundidad de cola) Requisitos previos: Phase 17 · 02 (Inference Platform Economics), Phase 17 · 04 (vLLM Serving Internals) Tiempo: ~75 minutos

Objetivos de Aprendizaje

  • Diagramar las tres capas de autoscaling (aprovisionamiento de nodos, gang scheduling, nivel de aplicación) y nombrar la herramienta utilizada en cada capa.
  • Explicar por qué DCGM_FI_DEV_GPU_UTIL es la señal de HPA incorrecta para vLLM y nombrar dos reemplazos (profundidad de cola, utilización de KV cache).
  • Describir gang scheduling y el modo de falla de asignación parcial que KAI Scheduler previene (7 de 8 GPUs inactivas).
  • Nombrar la política de consolidación de Karpenter (WhenEmptyOrUnderutilized) que finaliza trabajos de GPU en ejecución y definir la alternativa segura para 2026.

O Problema

Tu equipo implementa un servicio de atención de LLM en Kubernetes. Configuras HPA usando DCGM_FI_DEV_GPU_UTIL como señal. El servicio se clava en el 100% de utilización durante el horario comercial. HPA nunca escala hacia arriba (scale-up): ya cree que estás al límite. Agregas una réplica manualmente y el TTFT disminuye. Sin embargo, HPA sigue sin escalar. La señal te está mintiendo.

Por otro lado, usas Cluster Autoscaler para los nodos. Una solicitud de 1M de tokens llega a las 2 a.m.; el clúster pasa 3 minutos aprovisionando un nodo y la solicitud expira (timeout).

Además, implementas un modelo de 70B que requiere 8 GPUs distribuidas en 2 nodos. El clúster tiene 7 GPUs libres y 1 distribuida en 3 nodos. Cluster Autoscaler aprovisiona un nodo para la GPU faltante. Siete nodos esperan 4 minutos quemando dinero mientras Kubernetes pone a funcionar la última GPU.

Tres capas, tres modos de falla diferentes. En 2026, el autoscaling compatible con GPU no es simplemente "activar HPA". Consiste en componer el aprovisionamiento de nodos, gang scheduling y el escalado basado en señales de la aplicación.

El Concepto

Capa 1 — aprovisionamiento de nodos (Karpenter)

Karpenter monitorea los pods pendientes y aprovisiona nodos en aproximadamente 45 a 60 segundos (Cluster Autoscaler normalmente tarda de 90 a 120 segundos para nodos de GPU). Elige tipos de instancia de forma dinámica según la restricción del NodePool: si tu pod necesita 8 H100 y el clúster no tiene un nodo compatible, Karpenter aprovisiona uno directamente en lugar de escalar un grupo existente.

La trampa de la consolidación: la política predeterminada de Karpenter consolidationPolicy: WhenEmptyOrUnderutilized es peligrosa para los pools de GPU. Finalizará un nodo de GPU activo para migrar los pods a una instancia de tamaño adecuado más económica. Para las cargas de trabajo de inferencia, eso significa desalojar solicitudes en ejecución y volver a cargar un modelo de 70B en el nuevo nodo. La pérdida representa minutos de capacidad y fallas en las solicitudes.

Configuración segura para pools de GPU:

disruption:
  consolidationPolicy: WhenEmpty
  consolidateAfter: 1h

Permite que Karpenter consolide nodos verdaderamente vacíos después de una hora, pero nunca desaloje un trabajo activo.

Capa 2 — gang scheduling (KAI Scheduler)

KAI Scheduler (originalmente llamado proyecto "Karp" y luego renombrado) maneja lo que el kube-scheduler predeterminado no puede:

Gang scheduling — programación del tipo todo o nada. Un pod de inferencia distribuida que requiere 8 GPUs necesita que las 8 comiencen juntas o ninguna lo hará. Sin esto, caes en la trampa de la asignación parcial: 7 de los 8 pods inician, esperan indefinidamente y queman dinero.

Reconocimiento de topología (topology awareness) — saber qué GPUs comparten NVLink, cuáles están en el mismo rack y cuáles tienen InfiniBand entre ellas. Ubica los pods en consecuencia. Una carga de trabajo de paralelismo de tensores de DeepSeek-V3 de 67B debe permanecer en un solo dominio NVLink; KAI Scheduler respeta esa regla.

Colas jerárquicas — múltiples equipos compiten por el mismo pool de GPUs con prioridad y cuota. La urgencia de producción del Equipo A solo interrumpe el trabajo de entrenamiento del Equipo B si las reglas de prioridad lo permiten.

KAI se implementa junto con kube-scheduler como un agendador secundario; anotas las cargas de trabajo para usarlo. Las pilas de producción de Ray y vLLM se integran con KAI.

Capa 3 — señales a nivel de aplicación

La trampa de HPA: DCGM_FI_DEV_GPU_UTIL es una métrica de ciclo de trabajo: mide si la GPU estuvo realizando tareas en cada intervalo de muestreo. Una utilización del 100% podría significar 10 solicitudes concurrentes o 100; la GPU estuvo ocupada en ambos casos. Escalar basándose en el ciclo de trabajo es escalar a ciegas.

Peor aún, motores como vLLM preasignan la memoria del KV cache (hasta el límite de --gpu-memory-utilization). El uso de memoria se mantiene cerca del 90% incluso con una sola solicitud. HPA basado en memoria nunca realiza la reducción de escala (scale-down).

Señales de reemplazo para 2026:

  • Profundidad de la cola (solicitudes en espera para prefill).
  • Utilización del KV cache (qué fracción de bloques está asignada a secuencias activas).
  • TTFT P99 por réplica (tu señal de SLA).
  • Goodput (solicitudes que cumplen con todos los SLOs por segundo).

NVIDIA Dynamo Planner y llm-d Workload Variant Autoscaler consumen estas señales y escalan las réplicas. Reemplazan por completo a HPA para el servicio de LLMs.

Cuándo usar qué

Decisión de escala Herramienta
Agregar/eliminar nodos Karpenter
Programar tareas multi-GPU KAI Scheduler
Agregar/eliminar réplicas Dynamo Planner / llm-d WVA (o HPA personalizado en profundidad de cola)
Elegir tipo de GPU Karpenter NodePool
Prevenir baja prioridad Colas de KAI Scheduler

La separación (disaggregation) de prefill/decode lo complica todo

Si ejecutas prefill y decodificación de forma separada (Phase 17 · 17), tienes dos clases de pods con diferentes activadores de escala: los pods de prefill escalan según la profundidad de la cola, mientras que los pods de decodificación escalan bajo presión del KV cache. llm-d expone estos componentes como Services separados con HPA por rol. No intentes colocar un solo HPA frente a ambos.

El cold start también importa aquí

La mitigación de cold start (Phase 17 · 10) es donde el tiempo de aprovisionamiento de nodos se vuelve visible para el usuario. El tiempo de calentamiento de Karpenter de 45 a 60 segundos, sumado a la carga de un modelo de 20GB y la inicialización del motor, significa que una solicitud desde cero tarda de 2 a 5 minutos. Mantén un pool activo (min_workers=1) para rutas críticas de SLO o usa checkpoints al estilo de Modal en la capa de aplicación.

Números que debes recordar

  • Aprovisionamiento de nodos con Karpenter: ~45-60s vs Cluster Autoscaler ~90-120s (nodos de GPU).
  • KAI Scheduler evita el desperdicio de asignación parcial: la trampa de 7 de 8.
  • DCGM_FI_DEV_GPU_UTIL como señal de HPA: rota; usa profundidad de cola o utilización de KV.
  • WhenEmptyOrUnderutilized de Karpenter: finaliza trabajos de GPU activos. Usa WhenEmpty + consolidateAfter: 1h para inferencia.

Use It

code/main.py simula un autoscaler de tres capas en una carga de trabajo de GPU inactiva. Compara el HPA ingenuo (ciclo de trabajo), HPA por profundidad de cola y el escalado programado por gang de KAI. Informa solicitudes no atendidas, minutos de GPU inactiva y una puntuación compuesta.

Ship It

Esta lección produce outputs/skill-gpu-autoscaler-plan.md. Dada la topología del clúster, el perfil de la carga de trabajo y el SLO, diseña un plan de autoscaling de tres capas.

Exercises

  1. Ejecuta code/main.py. Bajo una carga de trabajo con ráfagas (bursty), ¿cuántas solicitudes descarta el HPA de ciclo de trabajo ingenuo que el HPA por profundidad de cola logra procesar? ¿De dónde proviene esa diferencia?
  2. Diseña un Karpenter NodePool para un clúster que atiende a Llama 3.3 70B FP8 en H100 SXM5. Especifica capacity-type, disruption.consolidationPolicy, consolidateAfter y un taint que mantenga las cargas de trabajo que no son de GPU fuera de estos nodos.
  3. Tu equipo informa que las implementaciones están atascadas en Pending porque "las GPUs están disponibles pero el pod no se programa". Diagnostica: ¿el problema es de Karpenter, de kube-scheduler o de KAI Scheduler? ¿Qué métricas lo confirman?
  4. Elige una señal para escalar automáticamente los pods de prefill desagregados y una señal diferente para los pods de decodificación. Justifica ambas.
  5. Calcula el costo de la trampa de consolidación WhenEmptyOrUnderutilized en un servicio de producción 24/7 que promedia 60 eventos de pérdida de solicitudes/día con TTFT P99 > 10s.

Key Terms

Term What people say What it actually means
Karpenter "el aprovisionador de nodos" Autoscaler de nodos de Kubernetes; aprovisionamiento en menos de un minuto
Cluster Autoscaler "el antiguo escalador" Predecesor del autoscaler de nodos de Kubernetes; más lento, basado en grupos
KAI Scheduler "el programador de GPU" Agendador secundario para gang + topología + colas
Gang scheduling "todo o nada" Programa N pods de forma atómica o pospone todos ellos
Topology awareness "reconocimiento de rack" Ubica pods según el NVLink/IB/ubicación física del rack
DCGM_FI_DEV_GPU_UTIL "utilización de GPU" Métrica de ciclo de trabajo; NO es una señal de escala para LLMs
Queue depth "solicitudes en espera" Señal correcta de HPA para escala limitada por prefill
KV cache utilization "presión de memoria" Señal correcta de HPA para escala limitada por decode
Consolidation "consolidación de Karpenter" Finalización de nodos para migración a tipos de instancias más baratas
WhenEmpty + 1h "consolidación segura" Política que no desaloja tareas de GPU activas

Further Reading

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).