«Autoescalado» designa en Kubernetes tres mecanismos distintos, y confundirlos es el motivo más común por el que un clúster que debería escalar no lo hace. Los pods escalan con un HorizontalPodAutoscaler, los nodos escalan con los límites de los worker pools y el control plane escala con la carga de la API. Este artículo explica cada uno y después recorre una prueba real que realizamos en un Kube-DC Managed Cluster, con los manifests para que puedas repetirla.

Tres cosas pueden escalar

Capa Qué escala En un Kube-DC Managed Cluster
Pods El número de réplicas de un Deployment o StatefulSet, guiado por una métrica como la CPU HorizontalPodAutoscaler estándar, con metrics-server ya instalado. Probado en este artículo
Nodos El número de máquinas worker disponibles para ejecutar esos pods Worker pools con límites mínimo y máximo por pool, según está documentado para la plataforma. No forma parte de nuestra prueba
Control plane Los recursos del API server y de etcd a medida que crece la carga del clúster Autoescalado vertical de ambos, activado por defecto y dentro de límites configurados, según está documentado. No forma parte de nuestra prueba

Etiquetamos cada capa según lo que hemos probado y lo que solo conocemos por la documentación, porque la diferencia importa al planificar la capacidad.

Qué hace realmente el HorizontalPodAutoscaler

El HorizontalPodAutoscaler (HPA) es un bucle de control que se ejecuta dentro del control plane de Kubernetes. Por defecto se activa cada 15 segundos, lee las métricas de los pods a los que apunta y ajusta el número de réplicas del Deployment. Entender cuatro detalles explica casi cualquier sorpresa:

  • La utilización es relativa al request. Un objetivo del 50 % de CPU significa el 50 % de la CPU solicitada por los contenedores del pod, no el 50 % del nodo. Si un contenedor no tiene un request de CPU, la utilización no está definida y el autoscaler no actúa para esa métrica.
  • Necesita la Metrics API. La API metrics.k8s.io la proporciona normalmente el complemento Metrics Server, que en un clúster autogestionado debe instalarse por separado.
  • El cálculo es una proporción. El número deseado de réplicas es igual al número actual de réplicas multiplicado por la proporción entre la métrica actual y el objetivo, redondeado hacia arriba. Si la proporción está dentro de una tolerancia de 0,1 en torno a 1,0, no ocurre nada.
  • El escalado a la baja es deliberadamente lento. El controlador recuerda las recomendaciones recientes y actúa según la más alta dentro de una ventana que por defecto dura cinco minutos, lo que suaviza las métricas fluctuantes y evita oscilaciones.

Por ejemplo, una réplica que funciona al 57 % de CPU frente a un objetivo del 50 % da una proporción de 1,14 y, redondeando hacia arriba, 1 × 1,14 da 2 réplicas. Es exactamente el primer paso que observamos en la prueba siguiente.

La prueba: escalar un Managed Cluster bajo carga real

En nuestra prueba de extremo a extremo de agosto de 2026 creamos un Managed Cluster llamado test2 con dos nodos worker, cada uno dimensionado con 1 vCPU y 2 GB de memoria para ajustarse al margen que quedaba en la cuota del paquete. El endpoint de API del clúster es privado por defecto, así que accedimos a él desde la Cloud Shell integrada del proyecto mediante la dirección de servicio interna del clúster, no desde Internet. Ambos workers estaban Ready y metrics-server ya estaba instalado y funcionando, como exige el HPA.

Desplegamos una pequeña aplicación web con un HPA que apunta al 50 % de CPU y un rango de 1 a 6 réplicas. Son manifests de ejemplo con la misma forma que los de la prueba; los valores de los requests de CPU son ilustrativos:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: nginxdemos/hello
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 100m
            memory: 64Mi
---
apiVersion: v1
kind: Service
metadata:
  name: hello
spec:
  selector:
    app: hello
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: hello
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: hello
  minReplicas: 1
  maxReplicas: 6
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

Para generar una carga sostenida, iniciamos varios pods desechables dentro del clúster, cada uno de los cuales lanza en bucle solicitudes HTTP contra el servicio. Ejecuta el primer comando en dos o tres shells con nombres distintos y observa el autoscaler en otra:

kubectl run load-1 --image=busybox:1.36 --restart=Never -- /bin/sh -c "while true; do wget -q -O- http://hello > /dev/null; done"

kubectl get hpa hello --watch
Resultado: la CPU subió al 57 % bajo carga, el HPA escaló el despliegue de 1 a 2 y luego a 3 réplicas, y la CPU media se estabilizó en torno al 35 %. Cuando se retiraron los generadores de carga, el número de réplicas volvió a 1 sin ninguna acción manual.

Dos notas honestas sobre ese resultado. No cronometramos el escalado a la baja, y la ventana de estabilización predeterminada de cinco minutos es la razón por la que va por detrás del escalado al alza. Y la prueba demuestra solo la capa de pods: muestra que el HPA, la Metrics API y la planificación del clúster funcionan juntos en un Kube-DC Managed Cluster, no cómo se comportan los worker pools con el escalado a nivel de nodo.

Cuando termines, retira la carga con kubectl delete pod load-1 (y con los demás generadores que hayas iniciado) y después la carga de trabajo de prueba con kubectl delete hpa,svc,deploy hello.

Lo que los pods no pueden hacer solos: la capacidad

El HPA añade pods, y los pods necesitan un lugar donde ejecutarse. Si los workers están llenos, las réplicas adicionales se quedan en Pending hasta que haya capacidad, por lo que el maxReplicas del HPA solo tiene sentido si el pool subyacente puede albergar tantos pods. Multiplica el número máximo de réplicas por los requests de cada pod y compara el resultado con la capacidad libre de tu worker pool.

En Kube-DC, los worker pools se definen por pool (CPU, memoria, disco e imagen) con límites de autoescalado por pool, y el pool toma recursos de la cuota de tu paquete. Esa cuota se comparte entre todo lo que ejecutas: contenedores, máquinas virtuales y Managed Clusters comparten el mismo presupuesto de vCPU y memoria. Vimos la consecuencia en nuestra prueba, en la que un Managed Cluster existente y una máquina virtual usaban unas 7,5 de las 8 vCPU de un paquete Pro y no dejaban sitio para un pod GPU. Por eso dimensionamos los workers de prueba con 1 vCPU y 2 GB. Considera tu paquete el techo de cada capa de escalado y comprueba el margen restante antes de subir un máximo.

El control plane también escala

Un clúster con muchos pods y escalado frecuente carga el API server y etcd. La documentación de Kube-DC afirma que los recursos del control plane y de etcd se dimensionan automáticamente de forma adecuada dentro de límites configurados a medida que crece la carga del clúster, con autoescalado vertical activado por defecto. En un clúster autogestionado, dimensionar correctamente esos componentes es cosa tuya, y etcd es sensible a la falta de recursos, como explicamos en nuestro artículo sobre Kubernetes managed vs. self-hosted.

Errores comunes

  • Sin resource requests. Sin un request de CPU no se puede calcular un objetivo de utilización y el HPA no hace nada para esa métrica.
  • Ignorar el comportamiento en el arranque. Un pod que consume mucha CPU mientras se inicializa puede desencadenar escalados al alza adicionales. La documentación de Kubernetes recomienda una startup probe, o una readiness probe que solo pase después del pico, y el controlador ignora las muestras de CPU de un pod durante su periodo de inicialización.
  • Escalar por CPU cuando la CPU no es el cuello de botella. La API autoscaling/v2 admite también memoria y métricas personalizadas, más adecuadas para cargas de trabajo guiadas por colas o limitadas por E/S.
  • Fijar el máximo sin comprobar la capacidad. Como se ha dicho arriba, las réplicas que superan lo que el pool puede albergar simplemente esperan en Pending.
  • Ejecutar una sola réplica en producción. Un mínimo de uno significa un solo pod mientras la carga es baja. Usa un mínimo más alto para todo lo que deba sobrevivir a la pérdida de un nodo.

Fuentes

Lecturas relacionadas

Ejecuta esta prueba en tu propio clúster

Cada paquete de Kube-DC incluye clústeres de Kubernetes anidados, creados desde tu proyecto en un portal de autoservicio, con metrics-server listo y tu cuota visible para que puedas planificar la capacidad. Detrás hay vCPU dedicadas, almacenamiento NVMe respaldado por Ceph, una IPv4 pública dedicada y almacenamiento de objetos compatible con S3, con soporte 24/7 por correo y tickets y un objetivo de resolución de 4 horas. Repite la guía anterior y comprueba por ti mismo cómo se mueven las réplicas.

Descubre Kube-DC Kubernetes