Hay un tipo de incidente a las 3 de la madrugada que ningún operador de Kubernetes quiere vivir: un pod descontrolado consume silenciosamente toda la memoria disponible en un nodo, desencadenando una cascada de evictions, OOMKills y un equipo de guardia con los nervios de punta. Lo más frustrante es que, en la mayoría de los casos, era completamente evitable. Una buena gestión de recursos en Kubernetes — concretamente, definir con criterio los requests y los limits — es una de las medidas con mayor impacto que puedes tomar para garantizar la estabilidad de tu clúster.

Y sin embargo, es uno de los pasos que más se omite, especialmente cuando los equipos van a toda velocidad. Los desarrolladores despliegan cargas de trabajo sin especificaciones de recursos, los ingenieros de plataforma heredan clústeres mal definidos, y antes de darte cuenta estás lidiando con problemas de vecinos ruidosos que son un auténtico dolor de cabeza para depurar. Esta guía está pensada precisamente para cambiar eso.

Requests vs limits: qué son y por qué la diferencia importa

Empecemos por los fundamentos. En Kubernetes, un resource request es el valor que utiliza el scheduler para decidir dónde colocar un pod. Es una garantía: el nodo debe tener al menos esa cantidad de CPU y memoria disponibles antes de que el pod se despliegue allí. Un resource limit, en cambio, es un techo — el máximo que un contenedor puede consumir.

Estos dos valores tienen propósitos muy distintos, y confundirlos trae problemas reales. Si defines los requests demasiado bajos, el scheduler sobrecomprometará los nodos más allá de su capacidad real. Si defines los limits demasiado bajos, provocarás throttling innecesario u OOMKills en cargas de trabajo perfectamente sanas. El objetivo es que ambos valores reflejen la realidad con la mayor precisión posible.

Cómo las clases QoS de Kubernetes condicionan el comportamiento ante evictions

Hay algo que no recibe suficiente atención: la relación entre tu configuración de recursos y las clases QoS de Kubernetes. Kubernetes asigna a cada pod uno de tres niveles de calidad de servicio, y esto afecta directamente qué pods se evictan primero cuando un nodo sufre presión de memoria.

  • Guaranteed: Los requests y los limits están definidos e igualados en todos los contenedores. Estos pods son los últimos en ser evictados.
  • Burstable: Al menos un contenedor tiene definido un request o un limit, pero no son iguales. Estos pods se evictan en función de su uso relativo respecto a sus requests.
  • BestEffort: No hay ningún request ni limit definido. Estos pods son los primeros en caer.

Si tienes servicios críticos sin especificaciones de recursos, sin quererlo los estás metiendo en la clase BestEffort — lo que significa que Kubernetes los sacrificará primero cuando haya escasez de recursos. Eso casi con toda seguridad no es lo que quieres para una API en producción o un pipeline de datos.

Conclusión clave: Kubernetes no sabe cuáles de tus cargas de trabajo son importantes a menos que se lo indiques. Los resource requests y limits son la forma en que comunicas prioridad al scheduler y al kubelet.

Pautas prácticas para definir los valores de recursos

¿Y cómo se eligen los números correctos? La respuesta honesta es: empieza por observar, no por adivinar. Si estás trabajando en un entorno de Kubernetes gestionado, tienes acceso a métricas a nivel de nodo que facilitan mucho este proceso. Herramientas como Prometheus y Grafana — o el Kubernetes Metrics Server si buscas algo más ligero — te permiten ver el consumo real de CPU y memoria a lo largo del tiempo.

Un punto de partida razonable para la mayoría de las cargas de trabajo:

  • Define tu memory request en torno al uso promedio observado bajo carga normal, y tu memory limit en aproximadamente 1,5 o 2 veces ese valor para absorber picos.
  • Para los CPU requests, usa el consumo promedio durante la operación habitual. Los CPU limits son más delicados — unos limits de CPU demasiado agresivos provocan throttling incluso cuando el nodo tiene capacidad de sobra, por lo que muchos equipos definen CPU requests pero dejan los CPU limits sin configurar para cargas de trabajo que no sean sensibles a la latencia.
  • Revisa estos valores con regularidad. Un servicio que gestionaba 100 peticiones por segundo hace seis meses puede tener un perfil de recursos muy diferente hoy.

Un patrón que merece la pena adoptar desde el principio es el Vertical Pod Autoscaler (VPA) en modo recomendación. No cambiará nada de forma automática, pero sí mostrará sugerencias basadas en el uso real — una comprobación muy útil frente a los valores que hayas configurado manualmente.

Gobernanza a nivel de namespace con LimitRanges y ResourceQuotas

La configuración individual de cada pod es solo la mitad de la historia. Para equipos que gestionan clústeres multitenancy o infraestructura compartida — algo habitual en entornos empresariales donde varias unidades de negocio comparten una misma plataforma — también necesitas controles a nivel de clúster.

Los LimitRanges te permiten definir requests y limits por defecto para un namespace, de modo que cualquier pod desplegado sin especificaciones de recursos herede unos valores sensatos. Es una forma sencilla pero muy efectiva de evitar que se cuelen pods en clase BestEffort.

Los ResourceQuotas van un paso más allá, limitando el total de CPU y memoria que todas las cargas de trabajo de un namespace pueden consumir de forma conjunta. Esto es especialmente valioso en clústeres de Kubernetes sobre bare metal — como los disponibles en la infraestructura de DIVERSITY — donde el sobrecompromiso tiene consecuencias directas sobre el hardware físico, sin la capa de abstracción del autoescalado de un proveedor cloud.

Los errores más comunes que debes evitar

Hay una serie de antipatrones que aparecen una y otra vez en entornos en producción, y vale la pena nombrarlos explícitamente.

Definir limits sin requests es más habitual de lo que parece. Si solo defines un limit, Kubernetes usa ese valor también como request, lo que puede llevar al scheduler a tomar decisiones de ubicación poco óptimas.

Usar valores idénticos para CPU requests y limits en todas las cargas de trabajo mete todo en la clase QoS Guaranteed, lo que suena bien pero en la práctica impide que las cargas de trabajo aprovechen la capacidad disponible cuando existe. En muchos casos es una restricción innecesariamente conservadora.

No revisar nunca las especificaciones de recursos es quizás el problema más extendido. Las aplicaciones cambian, los patrones de tráfico evolucionan y los perfiles de consumo se transforman. Trata tu configuración de recursos como un documento vivo, no como una tarea puntual que se hace una vez y se olvida.

La gobernanza de recursos como cuestión de soberanía digital

Hay un punto más amplio que merece atención, especialmente para organizaciones que operan sobre infraestructura cloud europea. La previsibilidad operativa es una forma de soberanía digital. Cuando entiendes y controlas cómo consumen recursos tus cargas de trabajo, dependes menos de mecanismos de autoescalado opacos y de sorpresas en la factura — dos factores que pueden erosionar la transparencia de costes que se supone que debe ofrecer gestionar tu propia infraestructura o una infraestructura gestionada.

Los equipos que ejecutan cargas de trabajo en los entornos de Kubernetes gestionado o bare metal de DIVERSITY se benefician de un nivel de visibilidad sobre la infraestructura que los grandes hyperscalers suelen ocultar. Pero esa visibilidad solo es útil si realmente estás gobernando bien tus cargas de trabajo. Los resource limits y requests son el punto de partida de esa gobernanza.

Próximos pasos

Configurar correctamente los requests y limits de Kubernetes no es una tarea que se hace una vez y listo — es una disciplina operativa continua. Empieza auditando los namespaces existentes en busca de pods sin especificaciones de recursos. Añade LimitRanges para aplicar valores por defecto. Instrumenta tus clústeres con herramientas de métricas para poder tomar decisiones basadas en evidencia y no en suposiciones.

Los beneficios son tangibles: menos OOMKills, un scheduling más predecible, mejor atribución de costes y un clúster que se comporta como esperas cuando está bajo presión. No es poca cosa cuando tienes cargas de trabajo en producción de las que depende tu negocio.

Si estás pensando en construir o migrar a un entorno Kubernetes donde tengas control real sobre tu infraestructura — sin el vendor lock-in ni la opacidad de los grandes hyperscalers — merece la pena explorar qué ofrece un Kubernetes gestionado o bare metal sobre infraestructura soberana europea.