Un Horizontal Pod Autoscaler configuré sur un déploiement dont les pods n’ont pas de requests CPU définis ne scale jamais correctement, et ce n’est pas un détail secondaire : c’est la condition silencieuse qui fait échouer le mécanisme au complet avant même qu’aucune ligne de configuration HPA ne soit lue.
Le calcul dépend d’un pourcentage, pas d’une valeur absolue
Le HPA cible un pourcentage d’utilisation d’une ressource, calculé relativement à la request posée sur le conteneur, pas relativement à une capacité machine ou à une valeur absolue.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: payment-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: payment-api
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Cette cible de 70 % signifie « 70 % de la CPU demandée dans les requests », pas 70 % d’un cœur physique. Sans request définie, le HPA n’a tout simplement aucune base de calcul et le contrôleur ne peut pas produire de décision de scaling cohérente. C’est la raison la plus fréquente d’un HPA qui semble configuré correctement mais ne scale jamais. L’autre prérequis silencieux, plus en amont encore : sans metrics-server installé sur le cluster, le HPA n’a aucune donnée à lire, quelle que soit la justesse des requests.
Comment le contrôleur décide du nombre de replicas
Le contrôleur HPA interroge périodiquement (toutes les 15 secondes par défaut) l’utilisation actuelle via les métriques agrégées sur une fenêtre de temps, et calcule le nombre de replicas voulu avec une formule simple : replicas désirés = replicas actuels × (utilisation actuelle / utilisation cible), arrondi au supérieur. Une charge à 140 % de la cible sur 4 replicas donne 4 × (140/70) = 8 replicas voulus.
Le piège de l’oscillation (flapping)
Sans garde-fou, un système qui scale up dès que la charge dépasse la cible et scale down dès qu’elle repasse en dessous peut osciller en boucle : scale up, la charge baisse mécaniquement avec plus de replicas, scale down, la charge remonte, scale up à nouveau. Chaque cycle a un coût réel (démarrage de nouveaux pods, période où ils ne sont pas encore prêts) sans stabiliser jamais la charge.
Le contrôleur intègre un délai de stabilisation par défaut : il n’accepte de scaler down qu’après une fenêtre de plusieurs minutes sans besoin de scale up, ce qui absorbe les pics ponctuels sans déclencher d’oscillation. Ce comportement est configurable finement :
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
Ce que le HPA ne résout pas
Le HPA scale le nombre de pods, jamais leurs ressources individuelles (c’est le rôle du Vertical Pod Autoscaler, un mécanisme distinct). Il ne résout rien non plus si le nœud sous-jacent manque de capacité pour accueillir de nouveaux pods : dans ce cas, c’est le cluster autoscaler (au niveau des nœuds, pas des pods) qui doit intervenir en complément. Un déploiement avec une seule replica ne bénéficie d’aucun scaling utile non plus : minReplicas doit être au moins 2 pour que le mécanisme ait un sens, et pour que la haute disponibilité tienne pendant une opération de scaling.
Où ça se range
Poser des requests honnêtes n’est pas seulement une question de scheduling ou d’éviction, comme le détaille l’article sur les requests et limits : c’est aussi le prérequis silencieux sans lequel l’autoscaling horizontal ne fonctionne pas du tout. Dimensionner correctement cette chaîne fait partie du socle posé lors d’une migration Kubernetes.
À retenir
Le HPA calcule ses décisions à partir d’un pourcentage de la request posée sur le conteneur, jamais d’une valeur absolue : sans request définie, aucun scaling cohérent n’est possible. La fenêtre de stabilisation au scale down évite l’oscillation. Le HPA scale le nombre de pods, ni leurs ressources individuelles ni la capacité des nœuds sous-jacents.