Les requests CPU et mémoire d’un pod sont presque toujours posées une fois, au moment d’écrire le manifeste, à partir d’une estimation, puis jamais revisitées malgré des mois de dérive entre la consommation réelle et cette valeur initiale. Le Vertical Pod Autoscaler existe précisément pour combler cet écart, à condition de comprendre pourquoi son mode le plus automatique n’est pas celui à activer en premier.
Une question différente de celle du HPA
Le HPA répond à « combien de pods faut-il ? » en ajoutant ou retirant des replicas selon une métrique de charge. Le VPA répond à une question distincte : « chaque pod a-t-il la bonne taille ? », en ajustant les requests CPU et mémoire à partir de la consommation réellement observée dans le temps, plutôt que d’une estimation figée à la création du manifeste.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: checkout-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: checkout
updatePolicy:
updateMode: "Off"
Trois modes, un seul sûr à activer sans réflexion
Le mode Off calcule une recommandation sans jamais l’appliquer : c’est le mode d’observation, celui qui permet de voir ce que le VPA propose avant de lui laisser toucher quoi que ce soit. Le mode Initial applique la recommandation uniquement à la création d’un nouveau pod, sans jamais toucher un pod déjà en cours d’exécution. Le mode Auto va plus loin : il redémarre un pod existant pour lui appliquer une nouvelle recommandation, ce qui signifie une interruption à chaque ajustement, potentiellement fréquente sur une charge qui varie beaucoup.
# La recommandation est visible sans jamais avoir été
# appliquée, même en mode Off
kubectl describe vpa checkout-vpa | grep -A6 "Recommendation"
Activer Auto sans avoir vérifié que ces redémarrages sont tolérables (un service sans tampon devant lui, sans plusieurs replicas pour absorber l’interruption d’une seule) transforme un outil d’optimisation en source d’instabilité auto-infligée.
Le conflit avec le HPA, souvent ignoré
Le VPA et le HPA agissent sur des axes différents mais peuvent se marcher sur les pieds : le HPA calcule sa cible de charge à partir de la request CPU du pod, tandis que le VPA modifie cette même request. Si les deux ciblent la même métrique (le CPU, typiquement) en même temps, chacun invalide la base de calcul de l’autre, un cycle qui peut osciller sans jamais se stabiliser.
# Combinaison sûre : VPA sur la mémoire uniquement,
# HPA sur le CPU, chacun sur son propre axe
resourcePolicy:
containerPolicies:
- containerName: "*"
controlledResources: ["memory"]
Le pattern qui évite le conflit : utiliser le VPA en mode Off pour dimensionner les requests une fois avec de vraies données, appliquer manuellement cette recommandation, puis laisser le HPA gérer le nombre de replicas sur cette base stabilisée — ou restreindre le VPA à une ressource que le HPA ne surveille pas (controlledResources: ["memory"] quand le HPA scale sur CPU).
Ce que le VPA ne corrige pas
Le VPA ajuste des requests à partir d’une consommation passée, ce qui suppose une charge relativement stable ou cyclique : un pic brutal et ponctuel (un import de données une fois par jour) fausse la recommandation si l’algorithme n’a pas assez d’historique pour distinguer le pic exceptionnel de la charge normale. Un dimensionnement basé sur le VPA reste une aide, pas un remplacement du jugement sur la nature réelle de la charge d’une application.
À retenir
Le VPA répond à une question que le HPA ne pose jamais : chaque pod a-t-il la bonne taille de requests, plutôt que d’en garder un nombre suffisant. Le mode Off (recommandation seule) est le point de départ systématique avant tout mode automatique ; le mode Auto a un coût réel d’interruption à chaque ajustement, à ne jamais activer sans avoir vérifié qu’il est tolérable. Combiné avec un HPA ciblant la même métrique, le VPA peut créer un cycle d’invalidation mutuelle : les séparer par ressource ou dimensionner une fois puis figer est le réflexe qui évite ce piège, un des ajustements fins qui accompagnent une migration Kubernetes une fois la charge réelle observée en production.