Kubernetes 1.33 y el redimensionado de pods en caliente: lo que la documentación no cuenta
La API responde en milisegundos, pero aplicar el cambio tarda entre 1 y 5 segundos y no avisa cuando falla: hay que sondear el estado y poner un timeout.
Kubernetes 1.33 graduó a GA la subresource pods/resize, esa que permite cambiar el límite de memoria de un contenedor sin reiniciarlo. Hasta ahí, el titular. El problema es lo que pasa después: la llamada a la API vuelve rápido, pero eso solo significa que el kubelet la ha aceptado, no que el ajuste esté en vigor. Un desarrollador que ha construido un sidecar open source sobre ese API se ha dedicado a medir el resto y ha publicado lo que se encuentra por el camino.
Los números que da son suyos, medidos en sus nodos: aplicar el cambio tarda entre 1 y 5 segundos, y más cuando la máquina está cargada. Si alguien monta algo sensible al tiempo encima de esto, ese es el presupuesto real, no la latencia de la llamada.
Aceptado no es aplicado
El pod recibe una condición PodResizePending con un motivo. Infeasible quiere decir que el kubelet ha decidido que no puede hacerlo, normalmente porque el allocatable del nodo está agotado, y no va a reintentar. Deferred es que está esperando. No hay callback de ningún tipo: se sondea la condición, y conviene ponerle un timeout, porque un resize también puede quedarse ahí parado indefinidamente. Este desarrollador se quedó en 60 segundos y, pasado ese punto, revierte el spec a lo que realmente está aplicado. Si no, spec y realidad se separan para siempre.
Hay un detalle de configuración que se lleva por delante todo el ejercicio: si no se pone restartPolicy: NotRequired para memoria en el contenedor, el kubelet lo reinicia en cada resize. Se pierde justo lo que se venía a buscar. Es fácil de olvidar porque se define por recurso y el valor por defecto no es el que uno quiere.
Decimales y el truco de subir solo el límite
Las cantidades decimales dan disgustos. Si el límite está escrito como 1500M y no como 1500Mi, el valor que el kernel acaba aplicando no es exactamente el que se pidió. Quien compruebe si el resize ha entrado comparando por igualdad no encontrará coincidencia nunca, y concluirá que hubo timeout cuando en realidad funcionó. Hay que normalizar a Mi antes de comparar.
Subir solo el límite es otra trampa. Las requests son lo que el scheduler reserva, así que la tentación de tocar únicamente el limit es grande. Mal camino: esa memoria se vuelve invisible para la contabilidad del scheduler, que coloca pods nuevos en espacio ya comprometido y sobrecompromete el nodo sin decir nada. Moviendo ambos, la admisión por allocatable del kubelet actúa como barrera real: cuando no hay sitio responde Infeasible en vez de dejar que el nodo reviente más tarde.
Queda el detalle de los cgroup namespaces privados. En EKS, leer /proc/self/mountinfo para localizar el cgroup del contenedor no funciona igual que en un host namespace, porque el campo root viene relativo. Hace falta un camino alternativo que haga glob por el UID del pod.
Nada de esto es difícil una vez se sabe, pero cada punto cuesta tiempo. El propio autor pide mediciones de latencia del kubelet más rigurosas que su horquilla de 1 a 5 segundos, porque es la cifra que acota para qué sirve de verdad esta API.

