Introducción
Preguntale a cualquier SRE cuál es el tamaño correcto para un servicio como checkout-api y vas a obtener respuestas contradictorias. Mientras los valores de Helm declaran replicas: 3, cpu: 1000m y memory: 2Gi, el estado real del clúster cuenta una historia distinta. El HPA escaló la aplicación a 11 réplicas debido a la carga de CPU; el VPA insiste en que está sobreaprovisionada, recomendando cpu: 350m; KEDA exige 24 réplicas por un pico de latencia en Kafka; y Karpenter ha provisionado dos nodos nuevos basándose en las solicitudes declaradas, no en el uso real.
Este escenario no es una anomalía, es el resultado arquitectónico esperado de utilizar herramientas modulares desacopladas. Kubernetes, siguiendo la filosofía Unix, ofrece componentes que hacen una cosa bien. Pero a diferencia de herramientas como grep o awk que procesan flujos secuenciales, los autoscalers ejecutan bucles de reconciliación concurrentes sobre los mismos campos de la API (spec.replicas, resources.requests). La falta de visibilidad cruzada entre estos controladores transforma la eficiencia modular en inestabilidad sistémica.
Qué ocurrió
El problema central radica en que el dimensionamiento de la carga de trabajo es una única ecuación matemática acoplada, no un conjunto de variables independientes. Cuando los equipos operacionales despliegan HPA (Horizontal Pod Autoscaler), VPA (Vertical Pod Autoscaler), KEDA y autoscalers de nodos como Karpenter o Cluster Autoscaler, cada uno asume un control exclusivo sobre su respectiva variable objetivo sin considerar las mutaciones de los demás.
Estos controladores actúan como reflejos biológicos: miden una señal de telemetría aislada y disparan una respuesta predefinida. El HPA reacciona al porcentaje de CPU, el VPA al uso histórico de memoria, KEDA a la profundidad de la cola de eventos y Karpenter a las solicitudes de recursos pendientes. Al no existir un «sistema nervioso central» que coordine estas acciones, los bucles de retroalimentación se desestabilizan. El resultado es un estado de thrashing, donde el sistema oscila violentamente entre estados de sobre- y sub-provisionamiento, degradando el rendimiento y aumentando los costos sin una lógica unificada de optimización.
Impacto para DevOps / Infraestructura / Cloud / Seguridad
La consecuencia operativa más directa es la degradación de los SLOs (Service Level Objectives) durante picos de tráfico. En entornos con GitOps (como Argo CD o Flux), la lucha entre autoscalers crea conflictos de estado. Si el HPA escala un despliegue a 20 réplicas para manejar una carga súbita, Argo CD puede marcar la aplicación como OutOfSync porque la definición en Git especifica 3 réplicas. Si la sincronización automática está habilitada, el motor de GitOps revierte el cambio, eliminando la capacidad crítica justo cuando el sistema más la necesita.
Desde la perspectiva de costos, el impacto es severo. Los autoscalers de nodos como Karpenter toman decisiones de colocación basándose estrictamente en las requests declaradas en los contenedores, no en el consumo real. Si un contenedor solicita 1000m de CPU pero solo consume 150m, el planificador reserva el núcleo completo. Esto multiplica la ineficiencia de dimensionamiento hacia la infraestructura física o virtualizada subyacente. Según datos reportados en flotas de producción, la utilización promedio de CPU en clústeres Kubernetes oscila alrededor del 8%, a pesar de un aprovisionamiento agresivo de nodos, generando desperdicios financieros significativos en proveedores como AWS, Azure o GCP.
Detalles técnicos
El mecanismo de fallo se manifiesta en cuatro modos de falla comunes derivados de la concurrencia de controladores:
Para diagnosticar la lucha entre autoscalers, los ingenieros pueden monitorear la frecuencia de eventos de HorizontalPodAutoscaler y VerticalPodAutoscaler en los logs del API server, o usar herramientas de observabilidad como Prometheus para correlacionar métricas de kube_horizontalpodautoscaler_status_desired_replicas con kube_verticalpodautoscaler_recommendation.
Qué deberían hacer los administradores y equipos técnicos
La solución inmediata no es eliminar herramientas, sino establecer jerarquías explícitas y desactivar conflictos conocidos.
ignoreDifferences:
– group: apps
kind: Deployment
jsonPointers:
– /spec/replicas
Conclusión
La automatización en Kubernetes no es lo mismo que la autonomía. Hoy en día, nuestros clústeres poseen actuadores eficientes (HPA, VPA, Karpenter) pero carecen de una inteligencia centralizada que entienda el panorama completo. La arquitectura actual fuerza a los equipos de SRE a actuar como coordinadores humanos de bucles de control que no se hablan entre sí.
El futuro del dimensionamiento de cargas de trabajo en la nube exige pasar de la automatización reactiva a la autonomía cerrada. Necesitamos sistemas que no solo ejecuten mutaciones de API, sino que comprendan los compromisos entre rendimiento, costo y riesgo, asumiendo la responsabilidad de fin a fin. Hasta que existan estas capas de orquestación inteligente nativas, la mitigación depende de una configuración consciente de los conflictos y una observabilidad profunda de las interacciones entre controladores.
Fuentes
https://thenewstack.io/why-kubernetes-autoscalers-fight/
