Introducción
Cuando un Pod en ejecución solicita un incremento de CPU o memoria y el nodo no tiene headroom suficiente, el Kubelet marca la operación como Deferred y el Pod queda estacionado sin fecha de resolución. En clusters donde los operadores maximizan la densidad con bin-packing agresivo de batch jobs y tareas best-effort, ese estado Deferred se vuelve permanente para workloads de alta prioridad. No hay timeout, no hay escalada automática, no hay intervención del scheduler.
Kubernetes v1.37 aborda esta brecha con la funcionalidad scheduler preemption for in-place Pod resize, activada bajo el feature gate InPlacePodVerticalScalingSchedulerPreemption en estado Alpha. El scheduler ahora intercepta Pods con condición Deferred, identifica workloads de menor prioridad en el mismo nodo y los evoca de forma controlada para liberar la capacidad que el resize necesita.
Qué ocurrió
La feature de in-place Pod resize llegó a General Availability en v1.35, permitiendo ajustar requests y limits de CPU y memoria de contenedores corrientes sin restart. El problema operativo apareció en la intersección entre esa capacidad dinámica y la lógica estática del scheduler: una vez que un Pod tiene spec.nodeName asignado, el scheduler lo excluye de la cola activa de scheduling. Si el resize queda Deferred, nadie lo reevalúa.
En v1.37, el scheduler introduce una excepción a esa regla. Monitoriza continuously los Pods que reportan resizeStatus: Deferred en status.containerStatuses[] y los mantiene en evaluación activa específicamente para disparar preemption. A diferencia de la preemption de placement, que recorre todos los nodos del cluster buscando el mejor fit, esta preemption está estrictamente localizada en el nodo donde el Pod ya corre. El scheduler identifica «victim Pods» de prioridad inferior en ese host y orquesta su eviction gracefully.
La separación de responsabilidades es un punto arquitectónico clave: el critical Pod admission handler del Kubelet deja de ejecutar preemption local para operaciones de resize in-place. El Kubelet se limita a deferir la request y delegar la decisión al scheduler, que opera con visibilidad global sobre prioridades, PodDisruptionBudgets y políticas de graceful termination.
Impacto para DevOps / Infraestructura / Cloud / Seguridad
Para equipos que gestionan clusters de producción con objetivos de utilization superiores al 70-80%, esta funcionalidad resuelve el trade-off entre densidad y resiliencia. Antes de v1.37, la única estrategia para garantizar que un in-memory database o un web server en tiempo real pudiera escalar in-place era reservar buffer de capacidad en cada nodo, degradando la eficiencia de costos. Con preemption localizada, el operador puede bin-pack con confianza: los batch jobs que ocupan el headroom residual se evocan automáticamente cuando un workload crítico necesita crecer.
El impacto en seguridad operativa es directo. Un resize Deferred que nunca se resuelve puede derivar en OOM kills progresivos, degradación de latencia o caída del servicio. El mecanismo de preemption acota ese riesgo sin intervención manual. Además, al centralizar la decisión de eviction en el scheduler, se respetan las PDBs y los grace periods configurados, evitando que la preemption de un resize dispare cascadas de terminaciones abruptas.
Para plataformas internas que ofrecen autoscaling vertical (VPA) o resize programático, la funcionalidad elimina la necesidad de custom controllers que monitoreen el estado Deferred y ejecuten eviction manual. El scheduler lo hace nativamente, con tracking continuo hasta que el Kubelet actúa el resize.
Detalles técnicos
El feature gate InPlacePodVerticalScalingSchedulerPreemption controla la habilitación. Sin este gate activo, el comportamiento de Deferred sin intervención del scheduler se mantiene idéntico a v1.35 y v1.36.
El scheduler trata los recursos solicitados para un resize Deferred como ya consumidos en sus cuentas internas. Esto previene double-allocation y race conditions entre la preemption y la actuation del Kubelet. Cuando el eviction de los victim Pods libera capacidad, el Kubelet detecta el espacio disponible y ejecuta el resize.
La preemption no migra el Pod ni lo reubica en otro nodo. Si el nodo actual no puede acomodar el resize incluso después de evictar todos los workloads de menor prioridad elegibles, la request permanece en Deferred. No hay fallback a otro nodo.
Un campo nuevo en el Node Spec, spec.podPreemptionPolicy, permite a administradores o autoscalers deshabilitar la preemption para resizes in-place en nodos específicos. El caso de uso documentado es un controlador que prefiere escalar hacia abajo otros Pods o ajustar la capacidad del nodo antes de recurrir a preemption como último recurso.
Si durante un ciclo de preemption activo se recibe un resize de prioridad superior para otro Pod en el mismo nodo, el Kubelet prioriza esa nueva request y el scheduler dispara una segunda ronda de preemption si la capacidad liberada no es suficiente.
Para testing local, el flujo con kind requiere un nodo con headroom limitado. El comando de creación:
kind create cluster \
–name resize-preemption-test \
–image kindest/node:v1.37.0 \
–config kind-config.yaml
Donde kind-config.yaml habilita el feature gate en kubeadmConfigPatches para el control-plane y workers. Una vez el cluster corre, se verifican los cores allocatables con kubectl describe node y se despliegan dos PriorityClasses (una alta para el workload que resizes, una baja para los victim Pods) más un Deployment de batch que consuma el headroom restante.
Qué deberían hacer los administradores y equipos técnicos
Para habilitar la funcionalidad en un cluster de prueba, actualicen a Kubernetes v1.37 y configuren el feature gate en el kube-scheduler:
apiVersion: kube-scheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
featureGates:
InPlacePodVerticalScalingSchedulerPreemption: true
Reinicien el kube-scheduler y confirmen con kubectl get componentstatuses o revisando los logs del scheduler que el gate cargó correctamente.
En producción, antes de activar el gate, auditen sus PriorityClasses y PDBs. La preemption respeta las PDBs, pero si un workload crítico tiene minAvailable: 100% en su PDB, nunca será victim Pod y el resize del Pod superior quedará Deferred indefinidamente. Validen que la cadena de prioridades cubra todos los workloads del cluster.
Para nodos donde la preemption automática no es deseable (nodos con licencias atadas, workloads stateful sin tolerancia a eviction), configuren spec.podPreemptionPolicy: Never en el Node Spec. Esto mantiene el comportamiento de Deferred sin intervención del scheduler en esos hosts específicos.
Monitoreen la métrica resize_status en los Pods y alerten si un resize permanece en Deferred más de un umbral configurable (recomendado: 5 minutos). Si la preemption no libera capacidad suficiente, el resize queda Deferred y requiere intervención manual o ajuste de límites.
Dado que la feature está en Alpha, no la habiliten en clusters productivos sin una fase de validación extendida. El feature gate puede cambiar de nombre o semántica entre releases alpha y beta.
Conclusión
La preemption localizada para in-place resize cierra un gap operativo que existía desde que Kubernetes permitió modificar recursos de Pods en ejecución sin restart. El scheduler deja de ser ciego ante Pods Deferred y asume la responsabilidad de liberar capacidad en el nodo correcto, respetando prioridades y disruption budgets. Para equipos que priorizan densidad de recursos en clusters compartidos, esta funcionalidad elimina el dilema entre eficiencia de costos y capacidad de respuesta ante picos de demanda. La maduración desde Alpha hacia Beta en releases futuros determinará cuándo adoptarla en producción sin restricciones.
Fuentes
- https://kubernetes.io/blog/2026/09/10/kubernetes-v1-37-scheduler-preemption-for-in-place-pod-resize-alpha/
