--- title: "Cómo configurar el Horizontal Pod Autoscaler en Kubernetes" description: "Instala metrics-server, crea un Horizontal Pod Autoscaler basado en CPU y memoria, ajusta la velocidad de escalado y compruébalo con una prueba de carga real." category: "Kubernetes Avanzado" language: es source: https://cubepath.com/es/docs/kubernetes-avanzado/escalador-automatico-horizontal-de-pods-de-kubernetes updated: 2026-09-25 --- # Cómo configurar el Horizontal Pod Autoscaler en Kubernetes El Horizontal Pod Autoscaler (HPA) ajusta automáticamente el número de réplicas de un Deployment o StatefulSet según el uso de recursos de sus pods: añade réplicas cuando la carga sube y las retira cuando baja. En este tutorial instalarás metrics-server, desplegarás una aplicación de ejemplo, crearás un HPA con la API `autoscaling/v2` que escala por CPU y memoria, ajustarás su comportamiento para evitar oscilaciones y lo verás actuar con una prueba de carga. ## Requisitos previos Para seguir esta guía necesitas: - Un clúster de Kubernetes 1.29 o superior con al menos dos nodos worker, por ejemplo desplegado con kubeadm sobre VPS de CubePath. - `kubectl` configurado contra el clúster con permisos de administrador. - Espacio libre en el clúster para unas 10 réplicas de un pod que pide 200m de CPU (unos 2 vCPU en total). ## Cómo decide el HPA el número de réplicas El controlador del HPA consulta las métricas cada 15 segundos y calcula las réplicas deseadas con esta fórmula: ```text réplicas deseadas = ceil(réplicas actuales × valor actual / valor objetivo) ``` Por ejemplo, con 2 réplicas al 100 % de CPU y un objetivo del 50 %, el HPA pide `ceil(2 × 100 / 50) = 4` réplicas. El porcentaje se calcula sobre las `requests` del contenedor, no sobre sus `limits`, así que **un pod sin `requests` de CPU no se puede escalar por CPU**. Si la diferencia con el objetivo es menor del 10 %, el HPA no hace nada, para evitar cambios constantes. ## Paso 1: Instalar metrics-server El HPA obtiene el uso de CPU y memoria de la API `metrics.k8s.io`, que publica metrics-server a partir de los datos del kubelet de cada nodo. Comprueba si ya lo tienes (algunas distribuciones como k3s lo incluyen): ```bash kubectl get deployment metrics-server -n kube-system ``` Si no existe, instala la última versión publicada por el proyecto: ```bash kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml ``` Espera un minuto y comprueba que devuelve datos: ```bash kubectl top nodes ``` ```output NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%) master-1 182m 9% 1320Mi 35% worker-1 95m 4% 980Mi 26% worker-2 88m 4% 1012Mi 27% ``` Si en su lugar ves `error: Metrics API not available` y el pod de metrics-server no llega a `Ready`, revisa sus logs: ```bash kubectl logs -n kube-system deploy/metrics-server ``` En clústeres kubeadm es habitual el error `x509: cannot validate certificate`, porque los kubelets usan certificados autofirmados. La solución correcta es que los kubelets pidan certificados firmados por la CA del clúster (`serverTLSBootstrap: true` en la configuración del kubelet y aprobar los CSR). En un clúster de pruebas puedes desactivar la verificación añadiendo el argumento `--kubelet-insecure-tls`: ```bash kubectl patch deployment metrics-server -n kube-system --type=json \ -p '[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]' ``` ## Paso 2: Desplegar una aplicación de ejemplo Usarás la imagen `hpa-example` del proyecto Kubernetes, un servidor PHP que realiza un cálculo costoso en cada petición y así consume CPU con facilidad. Crea el manifiesto: ```bash nano php-apache.yaml ``` ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: php-apache spec: replicas: 1 selector: matchLabels: app: php-apache template: metadata: labels: app: php-apache spec: containers: - name: php-apache image: registry.k8s.io/hpa-example ports: - containerPort: 80 resources: requests: cpu: 200m memory: 64Mi limits: cpu: 500m memory: 128Mi --- apiVersion: v1 kind: Service metadata: name: php-apache spec: selector: app: php-apache ports: - port: 80 ``` Las `requests` son imprescindibles: el objetivo del 50 % de CPU que usarás después significa 100m por pod. Aplica el manifiesto: ```bash kubectl apply -f php-apache.yaml kubectl rollout status deployment/php-apache ``` ```output deployment "php-apache" successfully rolled out ``` ## Paso 3: Crear el HPA Define el HPA con la API `autoscaling/v2`, que permite combinar varias métricas y configurar el comportamiento del escalado: ```bash nano php-apache-hpa.yaml ``` ```yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: php-apache spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: php-apache minReplicas: 1 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 ``` Con varias métricas, el HPA calcula las réplicas necesarias para cada una y aplica la mayor. Aplícalo y consulta su estado: ```bash kubectl apply -f php-apache-hpa.yaml kubectl get hpa php-apache ``` ```output NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache cpu: 1%/50%, memory: 14%/80% 1 10 1 30s ``` Si en `TARGETS` aparece ``, espera un minuto: el HPA necesita un par de ciclos para leer las primeras métricas. > Nota: escalar por memoria solo tiene sentido si la aplicación libera memoria cuando baja la carga. Muchos runtimes (JVM, Node.js) no la devuelven, y el HPA nunca reduciría réplicas. En ese caso escala solo por CPU. ## Paso 4: Generar carga y ver el escalado Abre una segunda terminal y lanza un pod que hace peticiones continuas al servicio: ```bash kubectl run load-generator --rm -it --image=busybox:1.36 --restart=Never -- \ /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done" ``` En la primera terminal, observa el HPA: ```bash kubectl get hpa php-apache --watch ``` En uno o dos minutos la CPU supera el objetivo y las réplicas aumentan: ```output NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache cpu: 1%/50%, memory: 14%/80% 1 10 1 3m php-apache Deployment/php-apache cpu: 248%/50%, memory: 15%/80% 1 10 1 4m php-apache Deployment/php-apache cpu: 248%/50%, memory: 15%/80% 1 10 4 4m php-apache Deployment/php-apache cpu: 71%/50%, memory: 16%/80% 1 10 6 5m ``` Detén el generador de carga con `Ctrl+C` en la segunda terminal. El HPA no reduce réplicas de inmediato: por defecto espera una ventana de estabilización de 5 minutos para no deshacer el escalado ante una bajada puntual. Pasado ese tiempo volverá a 1 réplica. Para ver las decisiones que ha tomado el HPA, revisa sus eventos: ```bash kubectl describe hpa php-apache ``` ```output Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulRescale 4m horizontal-pod-autoscaler New size: 4; reason: cpu resource utilization (percentage of request) above target Normal SuccessfulRescale 3m horizontal-pod-autoscaler New size: 6; reason: cpu resource utilization (percentage of request) above target ``` ## Paso 5: Ajustar el comportamiento del escalado El campo `behavior` controla la velocidad a la que el HPA añade y retira réplicas. Una configuración habitual para servicios web es escalar hacia arriba rápido y hacia abajo despacio. Edita el HPA: ```bash nano php-apache-hpa.yaml ``` Añade el bloque `behavior` dentro de `spec`, al mismo nivel que `metrics`: ```yaml behavior: scaleUp: stabilizationWindowSeconds: 0 policies: - type: Percent value: 100 periodSeconds: 15 - type: Pods value: 4 periodSeconds: 15 selectPolicy: Max scaleDown: stabilizationWindowSeconds: 300 policies: - type: Percent value: 50 periodSeconds: 60 selectPolicy: Min ``` Qué significa cada parte: | Campo | Efecto | |---|---| | `scaleUp.policies` | Cada 15 segundos puede duplicar las réplicas o añadir 4, lo que sea mayor (`selectPolicy: Max`). | | `scaleUp.stabilizationWindowSeconds: 0` | Escala hacia arriba en cuanto la métrica lo pide. | | `scaleDown.stabilizationWindowSeconds: 300` | Usa la recomendación más alta de los últimos 5 minutos antes de reducir. | | `scaleDown.policies` | Retira como máximo el 50 % de las réplicas por minuto. | Aplica el cambio y comprueba que el HPA lo ha aceptado: ```bash kubectl apply -f php-apache-hpa.yaml kubectl get hpa php-apache -o jsonpath='{.spec.behavior.scaleDown}{"\n"}' ``` ```output {"policies":[{"periodSeconds":60,"type":"Percent","value":50}],"selectPolicy":"Min","stabilizationWindowSeconds":300} ``` Repite la prueba de carga del paso 4 para ver cómo ahora las réplicas suben más deprisa y bajan de forma escalonada. ## HPA y Vertical Pod Autoscaler El Vertical Pod Autoscaler (VPA) no añade réplicas: cambia las `requests` de CPU y memoria de cada pod según su consumo real. No se instala con Kubernetes; es un proyecto aparte del repositorio `kubernetes/autoscaler`. No combines HPA y VPA sobre la misma métrica (por ejemplo, ambos sobre CPU), porque el VPA modifica las `requests` que el HPA usa como referencia y los dos se contradicen. Un uso seguro del VPA es el modo `Off`, que solo recomienda valores de `requests` para que los ajustes tú. ## Solución de problemas - **`TARGETS` muestra `` de forma permanente.** Ejecuta `kubectl describe hpa php-apache`. El evento `FailedGetResourceMetric` indica que metrics-server no funciona (vuelve al paso 1) o que algún contenedor del pod no declara `requests` para esa métrica, incluidos los sidecars. - **Las réplicas no pasan de `maxReplicas`.** Es el límite configurado. Si los pods nuevos se quedan en `Pending`, el clúster no tiene capacidad: revisa `kubectl describe pod` y añade nodos. - **Las réplicas no bajan.** Recuerda la ventana de estabilización de 5 minutos. Si escalas por memoria, comprueba con `kubectl top pods` si la aplicación libera memoria realmente. ## Conclusión Has instalado metrics-server, creado un HPA que escala por CPU y memoria y ajustado su comportamiento para reaccionar rápido ante picos sin oscilar al bajar. La clave está en definir `requests` realistas, porque todo el cálculo se basa en ellas. Como siguientes pasos, puedes escalar por métricas de la aplicación (peticiones por segundo, longitud de colas) con Prometheus y prometheus-adapter, probar KEDA para escalar según eventos externos, o añadir Cluster Autoscaler para que el clúster cree nodos cuando los pods nuevos no caben.