Introducción

Un equipo de plataforma que administra un clúster Kubernetes compartido con GPUs B200, H100 y B300 se enfrenta cada lunes a una cola de jobs pendientes del fin de semana. Los workloads de entrenamiento fallan con errores OOM porque el scheduler asignó pods a H100 (80GB VRAM) cuando necesitaban 150GB, mientras los nodos con B200 (192GB) permanecen ociosos. Los jobs de inferencia no se programan porque las particiones MIG pequeñas están agotadas, aunque hay slices más grandes disponibles en el mismo node. La solución actual es un script Bash de 200 líneas que cada 30 minutos reconfigura perfiles MIG, reschedulea jobs atascados y envía alertas a Slack o PagerDuty. El problema de fondo: Kubernetes treataba todas las GPUs como unidades idénticas.

Qué ocurrió

Kubernetes 1.34, liberado en abril de 2024, introdujo la Dynamic Resource Allocation (DRA), un cambio fundamental en el modelo de scheduling que resuelve estas limitaciones. Hasta ahora, el scheduler solo reconocía recursos GPU como una cantidad entera (nvidia.com/gpu: 1), sin distinguir modelos, capacidad de memoria o características hardware. Las soluciones alternativas —etiquetas de nodos, taints/tolerations, pools separados por tipo de GPU— requieren mantener manualmente múltiples definiciones de workloads y actualizar Helm charts cada vez que se agrega un nuevo modelo de GPU.

DRA permite que los drivers de GPU publiquen datos estructurados sobre sus capacidades, y que los pods expresen requisitos específicos usando Common Expression Language (CEL). Por ejemplo: «Asignar una H100 o mejor con al menos 40GB de memoria» o «Usar un slice MIG pequeño si hay disponible, sino mediano, o el GPU completo si es necesario». Esto elimina la necesidad de duplicar manifestos para cada generación de hardware y simplifica la gestión de clústeres heterogéneos.

Impacto para DevOps / Infraestructura / Cloud / Seguridad

Para los equipos de DevOps e Infraestructura, DRA reduce drásticamente la complejidad operativa. Ya no es necesario mantener scripts personalizados para reconfigurar MIG o reschedulear jobs, ni actualizar decenas de Helm charts al incorporar nuevos modelos de GPU. La asignación de recursos se vuelve declarativa y portáble: un mismo manifest funciona en clústeres con H100, B200, B300 o futuros modelos.

En Cloud, los proveedores como Azure Kubernetes Service (AKS) ya están adoptando DRA. Esto beneficia a los usuarios de servicios gestionados, que podrán aprovechar GPUs de manera más eficiente sin depender de soluciones propietarias. Para la Seguridad, el modelo de DRA mejora la isolation de recursos al permitir solicitudes más granulares (ej.: slices MIG específicos), reduciendo el riesgo de que un pod monopolice un GPU completo o acceda a memoria no asignada.

El impacto en eficiencia es significativo: en entornos con GPUs heterogéneas, DRA puede reduir el desperdicio de recursos entre un 20% y 40% al evitar la fragmentación de MIG y la subutilización de GPUs más potentes. Además, elimina los errores OOM causados por asignaciones incompatibles, mejorando la confiabilidad de los workloads de ML/AI.

Detalles técnicos

DRA se basa en tres componentes clave:

  1. Resource Management interface (RMI): Definida en KEP-2684, esta interfaz estandariza cómo los drivers (como el NVIDIA GPU Operator) exponen recursos dinámicos al kubelet. El driver registra los recursos disponibles (ej.: nvidia.com/gpu, nvidia.com/mig) y sus atributos (modelo, memoria, NVLink) a través de un plugin ResourceDriver que implementa la interfaz v1alpha1 del API de Kubernetes.
  1. Common Expression Language (CEL): Los pods especifican requisitos de recursos en el campo resourceClaims del pod spec, usando expresiones CEL para filtrar y priorizar recursos. Por ejemplo:
   resourceClaims:
     - name: gpu
       resourceTemplate:
         apiGroup: resource.k8s.io
         kind: GPU
         version: v1alpha1
       selection:
         matchLabels:
           nvidia.com/gpu.model: H100
         requirements:
           - pci/present: "true"
           - memory >= 40Gi
   
  1. Scheduler: El scheduler de Kubernetes fue modificado para evaluar las expresiones CEL y encontrar recursos que cumplan con los requisitos. El algoritmo de scheduling ahora considera la topología y características de los recursos, no solo su cantidad.

Para habilitar DRA en un clúster:

  • Usar Kubernetes 1.34 o superior.
  • Instalar el NVIDIA GPU Operator v1.2.0+, que incluye soporte para RMI.
  • Configurar el kubelet con la feature gate Resource Management=true (enabled by default en v1.34).
  • Definir una ResourceClass para cada tipo de recurso dinámico (ej.: nvidia.com/GPU).

Los perfiles MIG se exponen automáticamente como recursos separados (ej.: nvidia.com/mig-1g.10gb), pero los pods pueden usar CEL para solicitar flexibilidad:

selection:
  requirements:
    - nvidia.com/mig.size: 1g || nvidia.com/mig.size == 2g || nvidia.com/mig.size == 3g

Qué deberían hacer los administradores y equipos técnicos

  1. Verificar compatibilidad:
– Asegurarse de que el clúster ejecuta Kubernetes 1.34 o superior (consultar con kubectl version).

– Actualizar el NVIDIA GPU Operator a la versión 1.2.0 o posterior. En AKS, usar el add-on GPU-accelerated nodes con la versión de Kubernetes compatible.

  1. Habilitar DRA:
– En clústeres auto-gestionados, verificar que la feature gate Resource Management está habilitada en el kubelet (en v1.34+ está enabled by default).

– Crear las ResourceClass necesarias para los recursos dinámicos:

     kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi-external-snapshotter/client-v6/config/crd/bases/resourceclass.yaml
     kubectl create resourceclass nvidia-gpu nvidia.com/GPU --driver-name=nvidia.com/gpu
     
  1. Actualizar manifestos de workloads:
– Reemplazar resources: { nvidia.com/gpu: 1 } por resourceClaims con expresiones CEL. Por ejemplo, para un job que acepta cualquier GPU con al menos 40GB:
     resources:
       claims:
         - name: gpu
           resourceClaimTemplate:
             apiGroup: resource.k8s.io
             kind: GPU
             version: v1alpha1
             spec:
               parameters:
                 m ig.size: "2g"
                 memory: 40Gi
     

– Para Helm charts, definir los requisitos de recursos como valores configurables.

  1. Monitorear y ajustar:
– Usar kubectl get resourceclass para verificar las clases de recursos disponibles.

– Inspeccionar los recursos asignados a pods con kubectl get pod -o yaml (buscar el campo allocatedResources).

– Ajustar las expresiones CEL según las características del hardware y los requisitos de los workloads.

  1. Migración gradual:
– Comenzar con un grupo de nodos y workloads no críticos para validar la configuración.

– Usar podAffinity/podAntiAffinity para controlar la colocación durante la transición.

Conclusión

La Dynamic Resource Allocation en Kubernetes 1.34 marca un antes y después en la gestión de GPUs en entornos containerizados. Elimina las limitaciones del modelo de scheduling basado en cantidades enteras, permitiendo asignaciones granulares y adaptativas que coinciden con las necesidades reales de los workloads de AI/ML. Para los equipos de DevOps e Infraestructura, esto se traduce en menos scripts de mantenimientos, menos errors OOM y una utilización más eficiente de recursos costosos. Aunque la migración requiere actualizar components y manifestos, el esfuerzo se compensa con creces en clústeres heterogéneos o con MIG habilitado.

Fuentes

  • https://thenewstack.io/kubernetes-dra-gpu-scheduling/
  • https://kubernetes.io/blog/2024/04/19/dynamic-resource-allocation/

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *