El Horizontal Pod Autoscaler (HPA) permite ajustar automáticamente el número de Pods de una aplicación según métricas como el consumo de CPU. En esta guía vas a crear un laboratorio con un Deployment, un Service y un HPA basado en CPU; después generarás carga para comprobar el escalado ascendente y el retorno controlado al mínimo.

El laboratorio mantendrá entre 2 y 10 réplicas e intentará que el consumo medio se aproxime al 50 % de la CPU solicitada por cada Pod.

Alcance: el HPA escala Pods. No aumenta la CPU o memoria asignada a cada Pod ni crea nodos. Si el clúster no tiene capacidad suficiente, las réplicas nuevas quedarán en estado Pending.

Cómo funciona el Horizontal Pod Autoscaler

El controlador HPA consulta periódicamente las métricas disponibles mediante la API de Kubernetes. Después compara el valor actual con el objetivo configurado y actualiza el subrecurso scale del Deployment.

Cuando el objetivo está expresado como porcentaje de CPU, Kubernetes calcula la utilización respecto de resources.requests.cpu. Por esta razón, los contenedores deben declarar una solicitud de CPU: si falta, la utilización no queda definida correctamente y el HPA puede no actuar.

De forma simplificada, Kubernetes calcula las réplicas deseadas así:

réplicas deseadas =
techo(réplicas actuales × métrica actual / métrica objetivo)

El cambio no es instantáneo. El controlador también considera la disponibilidad de métricas, el estado Ready de los Pods, la tolerancia configurada y las ventanas de estabilización.

Los kubelets entregan métricas de CPU a Metrics Server; la API de Kubernetes las expone al controlador HPA, que ajusta el número de réplicas del Deployment y sus Pods.

Requisitos previos

Antes de comenzar, necesitas:

  • Un clúster Kubernetes activo y con capacidad para ejecutar hasta 10 réplicas pequeñas durante la prueba.
  • kubectl configurado con el contexto correcto.
  • Permisos para crear namespaces, Deployments, Services y recursos HPA.
  • Permisos para consultar métricas y eventos.
  • La API metrics.k8s.io disponible mediante Metrics Server u otro adaptador compatible.
  • Dos terminales: una para generar carga y otra para observar el escalado.
  • Acceso de salida desde los nodos hacia los registros de imágenes utilizados.
Advertencia: ejecuta este procedimiento en un namespace de laboratorio. La prueba genera carga y consume capacidad del clúster.

Paso 1: comprobar el contexto, los permisos y las métricas

Comprueba primero que kubectl apunta al clúster correcto:

kubectl config current-context
kubectl version --client

Valida los permisos necesarios:

kubectl auth can-i create namespace
kubectl auth can-i create deployment --namespace=hpa-lab
kubectl auth can-i create horizontalpodautoscaler.autoscaling \
  --namespace=hpa-lab

Las respuestas deberían ser yes. Si recibes no, solicita los permisos necesarios antes de continuar.

Comprueba ahora que la API de métricas está disponible:

kubectl get apiservice | grep metrics.k8s.io
kubectl get --raw '/apis/metrics.k8s.io/'
kubectl top nodes

El APIService correspondiente a metrics.k8s.io debería aparecer disponible y kubectl top nodes debería mostrar valores de CPU y memoria.

Las métricas pueden tardar unos minutos en aparecer cuando Metrics Server o los nodos acaban de iniciarse.

Si Metrics Server no está disponible

Instálalo mediante el procedimiento recomendado por la distribución o el proveedor del clúster. El proyecto ofrece un manifiesto genérico:

kubectl apply -f \
  https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

Antes de aplicarlo, revisa los requisitos oficiales de red, certificados, capa de agregación y compatibilidad.

No uses --kubelet-insecure-tls en producción para ocultar un problema de certificados. Esa opción desactiva la verificación del certificado presentado por el kubelet y debería limitarse, como máximo, a entornos de prueba controlados.

Paso 2: crear un namespace de laboratorio

Previsualiza el recurso antes de crearlo:

kubectl create namespace hpa-lab \
  --dry-run=client \
  -o yaml

Después crea el namespace y comprueba su estado:

kubectl create namespace hpa-lab
kubectl get namespace hpa-lab

Si el namespace ya existe y confirmaste que pertenece a esta prueba, no necesitas recrearlo.

Paso 3: preparar el Deployment, el Service y el HPA

Guarda el siguiente manifiesto como hpa-lab.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
  namespace: hpa-lab
spec:
  replicas: 2
  selector:
    matchLabels:
      app: php-apache
  template:
    metadata:
      labels:
        app: php-apache
    spec:
      containers:
        - name: php-apache
          image: registry.k8s.io/hpa-example:latest
          ports:
            - name: http
              containerPort: 80
          resources:
            requests:
              cpu: 200m
              memory: 64Mi
            limits:
              cpu: 500m
              memory: 128Mi
          readinessProbe:
            httpGet:
              path: /
              port: http
            initialDelaySeconds: 3
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /
              port: http
            initialDelaySeconds: 10
            periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: php-apache
  namespace: hpa-lab
spec:
  selector:
    app: php-apache
  ports:
    - name: http
      port: 80
      targetPort: http
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: hpa-lab
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 50
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300

La aplicación de demostración consume CPU al responder solicitudes. El valor requests.cpu: 200m funciona como referencia para el objetivo del 50 %.

El límite de 500m restringe el consumo individual del contenedor, pero no sustituye una prueba de capacidad del clúster.

La imagen registry.k8s.io/hpa-example:latest se utiliza para reproducir el laboratorio oficial de Kubernetes. En producción, emplea una imagen mantenida por tu equipo y fija una versión o un digest revisado.

Paso 4: validar antes de aplicar

Valida primero la sintaxis de manera local:

kubectl apply --dry-run=client -f hpa-lab.yaml

Después valida el manifiesto contra el esquema, las políticas de admisión y los permisos del servidor:

kubectl apply --dry-run=server -f hpa-lab.yaml

Revisa las diferencias que produciría la aplicación:

kubectl diff -f hpa-lab.yaml

kubectl diff devuelve el código 1 cuando encuentra diferencias. Esto es normal. Un código superior a 1 indica un error que debes resolver.

No continúes si la validación informa:

  • Un campo inválido.
  • Un recurso desconocido.
  • Una denegación de admisión.
  • Un namespace inexistente.
  • Falta de permisos.
  • Un scaleTargetRef que no coincide con el Deployment.

Paso 5: aplicar y comprobar el estado inicial

Aplica los recursos:

kubectl apply -f hpa-lab.yaml

Espera a que el Deployment esté disponible:

kubectl rollout status deployment/php-apache \
  -n hpa-lab \
  --timeout=120s

Consulta los recursos y las métricas:

kubectl get deployment,pods,service,hpa -n hpa-lab
kubectl top pods -n hpa-lab
kubectl describe hpa php-apache -n hpa-lab

El resultado esperado es:

  • El Deployment tiene 2 réplicas disponibles.
  • Los Pods aparecen como Running y Ready.
  • kubectl top pods muestra valores de CPU.
  • El HPA muestra una métrica actual en TARGETS, en lugar de <unknown>.
  • MINPODS es 2 y MAXPODS es 10.

Durante los primeros instantes, el HPA puede mostrar <unknown> mientras se recopilan las primeras muestras.

Paso 6: generar carga y observar el escalado

En la primera terminal, crea un Pod temporal que envíe solicitudes continuas al Service:

kubectl run load-generator \
  -n hpa-lab \
  --rm \
  -it \
  --image=busybox:1.36.1 \
  --restart=Never \
  -- \
  /bin/sh -c \
  'while sleep 0.01; do wget -q -O- http://php-apache; done'

En la segunda terminal, observa el HPA y los Pods:

kubectl get hpa,pods -n hpa-lab -w

Puedes registrar información adicional con:

kubectl top pods -n hpa-lab

kubectl get hpa php-apache \
  -n hpa-lab \
  -o 'custom-columns=NAME:.metadata.name,CURRENT:.status.currentReplicas,DESIRED:.status.desiredReplicas,CPU:.status.currentMetrics[0].resource.current.averageUtilization'

kubectl describe hpa php-apache -n hpa-lab

La prueba de escalado ascendente se considera satisfactoria cuando:

  • La CPU media supera el objetivo del 50 %.
  • DESIRED aumenta.
  • Aparecen más de 2 Pods.
  • El número de réplicas no supera maxReplicas: 10.
  • Los Pods nuevos alcanzan el estado Ready.
  • La aplicación continúa respondiendo.

La velocidad exacta depende del intervalo del controlador, la llegada de métricas, el tiempo de arranque y la capacidad disponible.

Paso 7: detener la carga y comprobar la reducción

Pulsa Ctrl+C en la terminal del generador de carga. Como se utilizó --rm, Kubernetes eliminará el Pod temporal.

Mantén la observación activa:

kubectl get hpa,pods -n hpa-lab -w

También puedes revisar las decisiones recientes del autoscaler:

kubectl describe hpa php-apache -n hpa-lab

La prueba de reducción se considera satisfactoria cuando:

  • El consumo de CPU desciende.
  • El HPA reduce las réplicas.
  • El Deployment vuelve a 2 Pods.
  • Los Pods restantes continúan disponibles.

La reducción no es inmediata. El manifiesto configura una ventana de estabilización de 300 segundos para evitar que una fluctuación breve provoque la eliminación y recreación repetida de Pods.

El retorno al mínimo puede tardar más de cinco minutos por la ventana configurada, la frecuencia de muestreo y la reconciliación del controlador.

En estado base hay dos Pods; al generar carga la CPU supera el 50 por ciento y el HPA aumenta réplicas; al detener la carga, una ventana de estabilización retrasa la reducción hasta volver a dos Pods.

Cómo retirar el HPA

Si quieres conservar la aplicación, pero dejar de escalar automáticamente, elimina primero el HPA:

kubectl delete hpa php-apache -n hpa-lab

Después establece manualmente el número de réplicas:

kubectl scale deployment/php-apache \
  -n hpa-lab \
  --replicas=2

Mientras el HPA esté activo, puede sobrescribir los cambios manuales realizados en spec.replicas.

kubectl rollout undo no revierte ni desactiva un HPA. Esa orden revierte una revisión del Deployment.

Cómo eliminar el laboratorio

Comprueba una vez más el contexto:

kubectl config current-context

Cuando confirmes que estás en el clúster correcto, elimina el namespace:

kubectl delete namespace hpa-lab --wait=true

Esta operación elimina todos los recursos namespaced contenidos en hpa-lab.

Problemas frecuentes

El HPA muestra <unknown> en TARGETS

Ejecuta:

kubectl top pods -n hpa-lab
kubectl get apiservice | grep metrics.k8s.io
kubectl describe hpa php-apache -n hpa-lab

Si las métricas no aparecen después de esperar las primeras muestras, revisa:

  • El estado y los logs de Metrics Server.
  • La conectividad entre Metrics Server y los kubelets.
  • Los certificados presentados por los kubelets.
  • La capa de agregación de la API.
  • Los permisos del adaptador de métricas.

El HPA recibe métricas, pero no aumenta las réplicas

Comprueba que:

  • Todos los contenedores relevantes declaran requests.cpu.
  • La carga llega al Service correcto.
  • El consumo medio supera realmente el objetivo.
  • El scaleTargetRef señala al Deployment adecuado.
  • Las condiciones y los eventos del HPA no muestran errores.

Una utilización cercana al objetivo puede quedar dentro de la tolerancia del controlador y no provocar cambios.

El HPA pide más réplicas, pero los Pods quedan Pending

El HPA ya calculó y solicitó el escalado. El problema se encuentra en la programación o en la capacidad del clúster.

Inspecciona uno de los Pods afectados:

kubectl describe pod NOMBRE_DEL_POD -n hpa-lab

Revisa:

  • CPU y memoria disponibles.
  • taints y tolerations.
  • Afinidad y antiafinidad.
  • Cuotas del namespace.
  • Límites configurados.
  • Restricciones de almacenamiento o red.

El HPA no crea nodos. Si no existe capacidad, necesitas ampliarla manualmente o utilizar un mecanismo de autoscaling de nodos compatible con la plataforma.

Las réplicas no bajan después de detener la carga

Revisa la utilización actual y la ventana de estabilización:

kubectl top pods -n hpa-lab
kubectl describe hpa php-apache -n hpa-lab

Comprueba también que:

  • No quede otro generador de carga activo.
  • Los Pods estén Ready.
  • Las métricas sean válidas.
  • Hayan transcurrido los 300 segundos de estabilización.

Las réplicas oscilan o la aplicación falla al escalar

Antes de modificar las políticas del HPA:

  • Ajusta los requests con mediciones reales.
  • Configura readinessProbe y startupProbe según el tiempo de arranque.
  • Comprueba que CPU represente la demanda del servicio.
  • Revisa si las dependencias soportan el aumento de concurrencia.
  • Conserva una ventana de estabilización suficiente.

Reducir la estabilización puede aumentar las oscilaciones si la métrica es ruidosa.

Buenas prácticas para producción

  • Define minReplicas según las necesidades de disponibilidad.
  • Limita maxReplicas según capacidad, cuotas, presupuesto y límites de las dependencias.
  • Configura los requests con información obtenida mediante pruebas de carga.
  • Fija las imágenes por versión o digest.
  • Diseña los Pods para que sean reemplazables y no dependan de archivos efímeros locales.
  • Utiliza probes coherentes con el arranque y la disponibilidad real.
  • Considera un PodDisruptionBudget cuando el nivel de servicio lo requiera.
  • Supervisa disponibilidad, latencia, errores, réplicas deseadas y capacidad.
  • No uses Metrics Server como sistema histórico de monitoreo.
  • Evalúa métricas personalizadas si CPU no representa correctamente la demanda.
  • Combina HPA con autoscaling de nodos solo cuando la plataforma lo permita y después de validar tiempos, límites y costos.

Conclusión

Un HPA funcional depende de cuatro elementos alineados:

  • Una métrica disponible.
  • Solicitudes de recursos correctamente definidas.
  • Un scaleTargetRef válido.
  • Capacidad para programar las nuevas réplicas.

La configuración no está terminada hasta observar el aumento de Pods bajo carga y el retorno controlado al mínimo.

Flujo de pods

Como siguiente paso, repite la prueba con un perfil de tráfico representativo y registra latencia, errores y consumo de recursos. Si CPU no se correlaciona con la demanda, utiliza una métrica de negocio, solicitudes por segundo o longitud de cola mediante una canalización compatible.

Cloud Serversby Donweb

Todo el poder de la nube a tus proyectos y aplicaciones.
Alojamiento ultra rápido, escalable y con alta disponibilidad.

  • Performance que te sorprenderá
  • Rápida escalabilidad y sin limitaciones
  • Arquitectura de alta disponibilidad
  • Soporte experto y ejecutivos de cuenta
  • Pagos en tu moneda y facturación local

Descubre la mejor solución de Cloud Hosting