Aller au contenu
Conteneurs & Orchestration medium

Horizontal Pod Autoscaler (HPA), Mise à l'échelle automatique

35 min de lecture

logo kubernetes

Le Horizontal Pod Autoscaler (HPA) ajuste automatiquement le nombre de réplicas d'une application pour suivre la charge observée. Il interroge périodiquement les métriques de vos Pods et augmente ou réduit leur nombre en fonction de seuils que vous définissez. C'est le mécanisme principal de mise à l'échelle horizontale dans Kubernetes.

Ce guide couvre la configuration du HPA avec autoscaling/v2, le rôle critique des requests, le contrôle du comportement de scaling, et le debug, tout ce qu'il faut pour la CKAD et la production.

  • Comment le HPA prend ses décisions et la formule de calcul
  • Le rôle critique des requests pour le calcul d'utilisation
  • Configurer un HPA basé sur CPU, mémoire ou plusieurs métriques
  • Contrôler la vitesse de scaling avec behavior
  • Débugger un HPA qui affiche <unknown> ou ne scale pas
  • Ce qu'il faut savoir pour la CKAD

Le HPA observe les métriques de vos Pods et ajuste leur nombre pour maintenir un niveau d'utilisation cible. Il ne réagit pas à un événement mais à une mesure : par défaut, le contrôleur réévalue la situation toutes les 15 secondes, compare la valeur observée au seuil et décide. Un point souvent mal compris : quand les métriques manquent, le HPA ne fait rien du tout, il ne revient pas à un nombre de réplicas par défaut.

SituationAction du HPA
Charge élevée (métriques > seuil)Augmente le nombre de réplicas
Charge faible (métriques < seuil)Réduit le nombre de réplicas (prudemment)
Métriques indisponiblesAttend sans modifier les réplicas

Ces trois mécanismes agissent à des étages différents et se complètent plus qu'ils ne se remplacent. Le HPA multiplie les Pods, le VPA les agrandit, le Cluster Autoscaler ajoute des nœuds quand il n'y a plus de place pour les accueillir. Attention en revanche à ne pas faire piloter la même métrique par le HPA et le VPA sur un même Deployment : les deux contrôleurs se contrediraient.

OutilAgit surCas d'usage
HPANombre de PodsApplications stateless, montée en charge
VPATaille des Pods (requests/limits)Applications avec besoins variables
Cluster AutoscalerNombre de nœudsCapacité cluster insuffisante

Avant de créer un HPA, deux éléments sont impératifs :

Le HPA récupère les métriques via le Metrics Server. Vérifiez qu'il est opérationnel :

Fenêtre de terminal
kubectl get deployment -n kube-system metrics-server
kubectl top pods -A

Si kubectl top affiche des valeurs CPU/mémoire, le Metrics Server fonctionne.

Installation si absent :

Fenêtre de terminal
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

C'est le point le plus important pour le HPA.

Pour un HPA basé sur averageUtilization, le calcul d'utilisation est :

Utilisation = (consommation actuelle / request) × 100

Sans requests définies, le HPA ne peut pas calculer le pourcentage d'utilisation et affichera <unknown> dans TARGETS.

# ✅ OBLIGATOIRE pour le HPA basé sur Utilization
resources:
requests:
cpu: "100m"
memory: "128Mi"

Le calcul du HPA est simple à énoncer, mais son application réelle comporte des garde-fous qui expliquent la plupart des comportements jugés « bizarres ». Comprendre la formule d'abord, puis les correctifs qui s'y greffent, évite de conclure trop vite qu'un HPA est cassé alors qu'il applique exactement sa règle.

Le HPA raisonne sur un ratio, pas sur un écart absolu : il compare l'utilisation moyenne constatée à l'objectif, puis multiplie le nombre de réplicas actuels par ce rapport. Le résultat est arrondi à l'entier supérieur.

Réplicas voulus = Réplicas actuels × (Utilisation actuelle / Objectif)

Exemple : 2 Pods à 80% d'utilisation, objectif 50%

Réplicas voulus = 2 × (80 / 50) = 3.2 → 4 Pods

La formule représente le principe général, mais le HPA applique aussi :

  • Une tolérance de ±10% avant de décider d'un scaling (évite les oscillations)
  • L'exclusion des Pods non Ready ou en cours de suppression
  • Une fenêtre de stabilisation avant de scale down (par défaut 5 minutes)
  • L'attente si des métriques sont manquantes

Cet exemple complet se déploie sur n'importe quel cluster de test disposant du Metrics Server. Il comporte trois pièces indissociables : un Deployment avec des requests, un Service pour recevoir la charge, et le HPA lui-même. Retirer les requests du premier suffit à rendre le troisième inopérant.

Le Deployment démarre à un seul réplica, c'est le HPA qui prendra la main ensuite. Notez que requests.cpu: "100m" (soit un dixième de cœur) sert de dénominateur au calcul d'utilisation : c'est cette valeur, et non la limite, qui détermine à partir de quelle consommation le seuil de 50 % est franchi.

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.28@sha256:146adea4768b83c607d0bdfa4188464e3da6e0a3ad4475db1d1d8f64f27c29cc
resources:
requests:
cpu: "100m" # ← OBLIGATOIRE pour le HPA
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP

Le champ scaleTargetRef désigne l'objet à redimensionner, ici le Deployment par son nom exact : une faute de frappe donne un HPA qui se crée sans erreur mais ne pilote rien. minReplicas et maxReplicas bornent la plage autorisée, et le maximum protège votre cluster d'une montée en charge incontrôlée.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50

Ce que ça signifie : Le HPA maintiendra l'utilisation CPU moyenne des Pods autour de 50%. Si elle dépasse, il ajoute des Pods. Si elle descend, il en retire (après stabilisation).

La colonne TARGETS est celle à surveiller : elle affiche l'utilisation constatée face à l'objectif. Comptez une à deux minutes avant qu'un chiffre apparaisse, le temps que le Metrics Server collecte ses premiers échantillons ; jusque-là, la valeur reste <unknown> sans que cela indique une erreur de configuration.

Fenêtre de terminal
kubectl apply -f nginx-deployment.yaml
kubectl apply -f nginx-hpa.yaml
kubectl get hpa
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
# nginx-hpa Deployment/nginx-deployment 10%/50% 1 10 1

Le HPA avec autoscaling/v2 supporte quatre types de métriques :

TypeDescriptionExemple
ResourceCPU, mémoire des conteneursaverageUtilization: 50
PodsMétrique agrégée par PodRequêtes/seconde par Pod
ObjectMétrique liée à un objet K8sRequêtes sur un Ingress
ExternalMétrique externe au clusterQueue AWS SQS, Pub/Sub

Combiner CPU et mémoire couvre le cas fréquent d'une application dont la charge se traduit tantôt par du calcul, tantôt par de l'occupation mémoire. Les deux entrées sont indépendantes, chacune avec son propre seuil.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: multi-metric-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 20
metrics:
# Métrique 1 : CPU
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
# Métrique 2 : Mémoire
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70

Pour les métriques custom (Pods, Object) ou external, vous avez besoin d'un adaptateur de métriques comme :

  • Prometheus Adapter, expose les métriques Prometheus au HPA
  • KEDA, autoscaler événementiel avec nombreuses sources

Le Metrics Server seul suffit uniquement pour CPU et mémoire.

Le champ behavior permet de contrôler finement la vitesse de scale up et scale down :

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: controlled-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # Attendre 5 min avant scale down
policies:
- type: Percent
value: 10 # Réduire max 10% par période
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0 # Scale up immédiat
policies:
- type: Percent
value: 100 # Doubler si nécessaire
periodSeconds: 15
- type: Pods
value: 4 # Ou ajouter max 4 pods
periodSeconds: 15
selectPolicy: Max # Prendre la politique la plus agressive

Deux notions se cumulent ici et sont souvent confondues. La fenêtre de stabilisation décide quand le HPA a le droit d'agir, en lissant les recommandations sur une période. Les politiques décident de combien il peut bouger sur un intervalle donné, en nombre de Pods ou en pourcentage. selectPolicy arbitre enfin entre plusieurs politiques déclarées.

ParamètreDescriptionDéfaut
stabilizationWindowSecondsTemps d'attente avant d'appliquer le scaling300s (down), 0s (up)
policies[].typePods (nombre absolu) ou Percent-
policies[].valueValeur du changement-
policies[].periodSecondsPériode d'évaluation-
selectPolicyMax, Min, ou DisabledMax

Ce réglage convient aux applications dont le démarrage est coûteux (chargement d'un modèle, remplissage d'un cache), où retirer un Pod trop tôt se paie cher si la charge revient. Descendre d'un seul Pod par minute après dix minutes d'accalmie assume un surcoût d'infrastructure en échange de la stabilité.

behavior:
scaleDown:
stabilizationWindowSeconds: 600 # 10 minutes
policies:
- type: Pods
value: 1 # 1 pod max par minute
periodSeconds: 60

Scale-to-zero : descendre à 0 réplica (Alpha, amélioré en 1.36)

Section intitulée « Scale-to-zero : descendre à 0 réplica (Alpha, amélioré en 1.36) »

Par défaut, minReplicas doit être ≥ 1. C'est volontaire : avec une métrique CPU ou mémoire, on ne peut pas connaître la charge sans pod en marche, donc le HPA ne saurait jamais quand redémarrer. Pour des workloads pilotés par une queue de messages ou un événement externe, ce raisonnement ne tient plus : c'est précisément le cas que résout le scale-to-zero.

Le feature gate HPAScaleToZero (KEP-2021) est Alpha depuis Kubernetes 1.16 et n'est pas activé par défaut. Kubernetes 1.36 améliore le comportement scale-to/from-zero quand le gate est actif (PR #135118), mais le statut Alpha reste inchangé. Sans le gate, l'API rejette minReplicas: 0 avec must be greater than or equal to 1.

Sur kubeadm, ajouter --feature-gates=HPAScaleToZero=true dans /etc/kubernetes/manifests/kube-apiserver.yaml. Sur k3s/k3d, passer le flag à la création :

Fenêtre de terminal
k3d cluster create demo \
--image rancher/k3s:v1.36.0-k3s1 \
--k3s-arg "--kube-apiserver-arg=feature-gates=HPAScaleToZero=true@server:0"

L'API Server impose une règle stricte avec minReplicas: 0 :

spec.metrics: Forbidden: must specify at least one Object or External metric to support scaling to zero replicas

Vous devez utiliser au moins une métrique Object ou External. Une métrique Resource (CPU/mémoire) est incompatible avec le scale-to-zero, c'est cohérent avec le raisonnement qui précède.

Avec le feature gate HPAScaleToZero=true, le Deployment descend à 0 desired replicas dès que la métrique passe sous le seuil, et remonte dès qu'elle dépasse la cible.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
namespace: hpa-test
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 0
maxReplicas: 5
metrics:
- type: External
external:
metric:
name: queue_messages
target:
type: Value
value: "10"
Fenêtre de terminal
kubectl apply -f hpa-scale-to-zero.yaml
kubectl get hpa -n hpa-test
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
# nginx-hpa Deployment/nginx <unknown>/10 0 5 0

REPLICAS=0 confirme le comportement. Le déploiement remontera automatiquement dès qu'un fournisseur de métriques externes (Prometheus Adapter, KEDA, custom-metrics-apiserver) renverra queue_messages > 10.

KEDA reste pertinent même si vous activez HPAScaleToZero :

CritèreHPA scale-to-zero (natif)KEDA
Activation feature gateRequis (Alpha)Pas nécessaire
Disponible sur cluster managéNonOui
Connecteurs (Kafka, RabbitMQ, AWS SQS, …)À implémenter70+ scalers prêts à l'emploi
MaturitéAlpha, en évolutionStable depuis 2021
Cas idéalDémo, lab, cluster auto-géré simpleProduction, multi-source

Un HPA qui n'a jamais scalé n'est pas un HPA validé. Le test consiste à générer assez de charge pour dépasser le seuil, observer la montée, puis couper la charge et vérifier la descente. Prévoyez deux terminaux : l'un pour la charge, l'autre pour kubectl get hpa -w qui affiche les transitions en direct.

Plutôt que d'installer des outils sur votre machine, générez la charge depuis un Pod dans le cluster :

Fenêtre de terminal
# Lancer un Pod de charge avec wget en boucle
kubectl run load-generator --image=busybox:1.36 --rm -it -- /bin/sh -c \
"while true; do wget -q -O- http://nginx-service; done"

Dans un autre terminal, observez le HPA :

Fenêtre de terminal
kubectl get hpa -w
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
# nginx-hpa Deployment/nginx-deployment 12%/50% 1 10 1
# nginx-hpa Deployment/nginx-deployment 78%/50% 1 10 1
# nginx-hpa Deployment/nginx-deployment 78%/50% 1 10 2
# nginx-hpa Deployment/nginx-deployment 45%/50% 1 10 2

Arrêtez la charge avec Ctrl+C et observez :

Fenêtre de terminal
kubectl get hpa -w
# Après plusieurs minutes...
# nginx-hpa Deployment/nginx-deployment 5%/50% 1 10 2
# nginx-hpa Deployment/nginx-deployment 5%/50% 1 10 1

Quand un HPA ne fait rien, la cause se situe presque toujours en amont de lui : métriques absentes, requests manquantes ou cible mal désignée. Le diagnostic suit donc la chaîne à rebours, du HPA vers le Metrics Server, plutôt que d'ajuster les seuils au hasard.

kubectl get hpa donne l'état en une ligne, describe fournit les conditions et les événements, qui contiennent le message d'erreur exact. Les deux commandes kubectl top servent ensuite à vérifier que le Metrics Server répond, indépendamment du HPA.

Fenêtre de terminal
# Vue rapide
kubectl get hpa
# Détails complets avec conditions et événements
kubectl describe hpa nginx-hpa
# YAML avec status actuel
kubectl get hpa nginx-hpa -o yaml
# Vérifier les métriques des Pods
kubectl top pods -l app=nginx
# Vérifier le Metrics Server
kubectl top nodes

kubectl describe hpa affiche des conditions qui expliquent l'état du HPA :

Fenêtre de terminal
kubectl describe hpa nginx-hpa
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True ReadyForNewScale recommended size matches current size
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count
ScalingLimited False DesiredWithinRange the desired count is within the acceptable range
ConditionSignification
AbleToScale: TrueLe HPA peut modifier les réplicas
ScalingActive: TrueLes métriques sont disponibles et valides
ScalingLimited: TrueBloqué par minReplicas ou maxReplicas

Le symptôme TARGETS: <unknown> revient trois fois dans ce tableau avec trois causes distinctes, c'est le piège principal du HPA : l'affichage est identique, seul le message de kubectl describe hpa permet de trancher.

SymptômeCause probableSolution
TARGETS: <unknown>/50%Pas de requests définiesAjouter resources.requests au Deployment
TARGETS: <unknown>/50%Metrics Server absentInstaller le Metrics Server
TARGETS: <unknown>/50%Pods pas encore ReadyAttendre que les Pods démarrent
ScalingActive: FalseMétrique introuvableVérifier le nom de la métrique
HPA ne scale pas upCharge insuffisanteAugmenter la charge de test
HPA ne scale pas downStabilization windowAttendre 5+ minutes
ScalingLimited: TruemaxReplicas atteintAugmenter maxReplicas

Si les conditions ne suffisent pas, il reste à interroger l'API de métriques directement. Un appel --raw sur metrics.k8s.io qui renvoie une liste vide prouve que le problème vient du Metrics Server et non du HPA.

Fenêtre de terminal
# Voir les événements du HPA
kubectl describe hpa nginx-hpa | grep -A 10 "Events:"
# Vérifier que la cible existe
kubectl get deployment nginx-deployment
# Vérifier les métriques brutes
kubectl get --raw "/apis/metrics.k8s.io/v1beta1/namespaces/default/pods" | jq .

kubectl autoscale crée un HPA sans écrire une ligne de YAML, ce qui fait gagner un temps précieux en examen. La contrepartie est réelle : la commande produit un objet autoscaling/v1, limité au CPU et dépourvu de behavior. Elle convient pour un besoin simple ou comme point de départ à compléter.

Fenêtre de terminal
# Créer un HPA basé sur CPU
kubectl autoscale deployment nginx-deployment \
--cpu-percent=50 \
--min=1 \
--max=10
# Vérifier
kubectl get hpa nginx-deployment

--dry-run=client construit l'objet localement sans l'envoyer à l'API, et -o yaml l'écrit sur la sortie standard. C'est le moyen le plus rapide d'obtenir un squelette correct, à enrichir ensuite avec des métriques supplémentaires ou un bloc behavior.

Fenêtre de terminal
kubectl autoscale deployment nginx-deployment \
--cpu-percent=50 --min=1 --max=10 \
--dry-run=client -o yaml > hpa.yaml

L'examen ne demande pas d'écrire un HPA sophistiqué : il vérifie que vous savez en créer un rapidement, lire son état et expliquer pourquoi il ne fonctionne pas. Les cinq points ci-dessous couvrent l'essentiel de ce qui tombe réellement.

  1. Lire un HPA existant

    Fenêtre de terminal
    kubectl get hpa
    kubectl describe hpa <nom>
  2. Créer un HPA CPU rapidement

    Fenêtre de terminal
    kubectl autoscale deployment <nom> --cpu-percent=50 --min=1 --max=10
  3. Comprendre le lien requests → HPA

    Sans requests, le HPA affiche <unknown> et ne fonctionne pas.

  4. Vérifier les métriques

    Fenêtre de terminal
    kubectl top pods
    kubectl top nodes
  5. Diagnostiquer TARGETS <unknown>

    • Metrics Server installé ?
    • requests définies dans le Deployment ?
    • Pods en état Running ?

Ces commandes couvrent le cycle complet : créer, observer, mesurer, ajuster, supprimer. kubectl patch mérite une mention particulière, il permet de relever maxReplicas sans rejouer le manifeste entier.

Fenêtre de terminal
# Créer rapidement
kubectl autoscale deployment myapp --cpu-percent=50 --min=2 --max=10
# Voir l'état
kubectl get hpa
kubectl describe hpa myapp
# Voir les métriques
kubectl top pods
kubectl top pods -l app=myapp
# Modifier à chaud
kubectl patch hpa myapp -p '{"spec":{"maxReplicas":20}}'
# Supprimer
kubectl delete hpa myapp

Trois situations reviennent en boucle et se ressemblent de loin : le HPA n'obtient aucune métrique, il en obtient mais reste immobile, ou il bouge trop. Chacune a une cause et une correction distinctes.

Cet événement apparaît dans la sortie de kubectl describe hpa. Il signifie que le contrôleur a bien interrogé l'API de métriques mais n'a rien reçu d'exploitable pour ce Deployment.

Warning FailedComputeMetricsReplicas unable to get metrics for resource cpu:
no metrics returned from resource metrics API

Cause : Le Metrics Server ne retourne pas de métriques pour ce Pod.

Solution :

Fenêtre de terminal
# Vérifier le Metrics Server
kubectl get deployment -n kube-system metrics-server
kubectl logs -n kube-system deployment/metrics-server
# Vérifier que les Pods ont des requests
kubectl get deployment nginx-deployment -o yaml | grep -A5 resources

Ici les métriques remontent correctement, le HPA a simplement décidé de ne rien faire. Vérifiez les trois explications suivantes avant de suspecter un dysfonctionnement.

Causes possibles :

  1. La charge est insuffisante (utilisation < 50% × tolérance)
  2. minReplicas: 1 empêche de descendre plus bas
  3. ScalingLimited: True, vérifier maxReplicas

Cause : La charge varie autour du seuil et provoque des scale up/down répétés.

Solution : Augmenter la fenêtre de stabilisation :

behavior:
scaleDown:
stabilizationWindowSeconds: 600
scaleUp:
stabilizationWindowSeconds: 60

Ce court quiz reprend les points les plus discriminants du guide : le rôle des requests, la lecture des conditions et la différence entre scale up et scale down.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

7 questions
5 min.
80% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  1. Le HPA ajuste le nombre de réplicas, pas la taille des Pods (c'est le VPA)
  2. Les requests sont obligatoires pour averageUtilization, sans elles, <unknown>
  3. Le Metrics Server est requis pour les métriques CPU/mémoire standard
  4. Le scale down est volontairement lent (5 min par défaut) pour éviter les oscillations
  5. behavior permet de contrôler finement la vitesse de scaling
  6. kubectl describe hpa montre les conditions et événements pour débugger
  7. kubectl autoscale crée rapidement un HPA CPU (utile pour la CKAD)
  8. Pour les métriques custom/external, il faut un adaptateur (Prometheus Adapter, KEDA)

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn