Sommaire
L’allocation par namespace est sortie, la direction financière a lu le tableau, et la question suivante tombe : combien de ce chiffre correspond à de la capacité réservée et jamais consommée ? On vous demande alors de baisser les requests de trois applications. Le propriétaire applicatif, lui, ne pose qu’une question, et elle est bien meilleure : qu’est-ce qui arrive exactement à mon pod quand quelqu’un change ce nombre ?
Cet article répond à celle-là. Il ne vend pas un gain : il déroule une chaîne de causalité bornée par version — où va le chiffre, qui le lit, qui le change, et ce que le kubelet en fait. Les deux outils du titre n’occupent pas la même place dans cette chaîne, et c’est le cœur du texte : KRR recommande et explique, VPA recommande et applique. Ce ne sont pas deux produits rivaux, ce sont deux étages. Aucun lab n’a été exécuté ici : ce qui suit est un travail de lecture des fichiers sources des projets amont, avec ses trous signalés à voix haute et toutes les valeurs d’instance laissées en REPLACE_WITH_*.
TL;DR
- La décision : écrire
updateModeexplicitement sur chaque objetVerticalPodAutoscaler, y compris quand la réponse estOff. La référence d’API du projet publie « Controls when autoscaler applies changes to the pod resources. The default is ‘Recreate’. » Un objet VPA sans ce champ évince des pods pendant que vous croyez « juste regarder ». - L’arbitrage qui coûte :
controlledValuesvautRequestsAndLimitspar défaut, et la documentation précise que « the limit is scaled proportionally to the request ». Vous croyez n’agir que sur la réservation d’ordonnancement ; vous déplacez aussi le plafond d’exécution, donc le seuil d’OOM, sur une charge dont lalimitmémoire était justement la marge de sécurité. - L’action de lundi matin : exécuter les deux requêtes PromQL de cet article pour obtenir votre ratio
requested/usedpar namespace, puis descendre au conteneur avant toute décision. Ce blog ne publiera aucune moyenne de parc à la place.
Ce que cet article chiffre — et ce qu’il refuse de chiffrer
Cette série publie une section de contrat de chiffre en tête de chaque article. Elle est destinée au lecteur, pas au rédacteur.
Ce que cet article publie : des numéros de version et des états de mécanisme (alpha, bêta, stable, GA, déprécié, retiré) ; des valeurs par défaut de paramètres, avec l’outil et le fichier qui les publient ; des percentiles et des fenêtres d’agrégation, cités comme défauts d’outil et jamais comme bonnes pratiques ; une requête PromQL que vous exécutez sur votre cluster.
Ce que cet article ne publie pas : aucun montant, aucune devise, aucun coût unitaire ; aucun pourcentage d’économie, ni le sien, ni celui d’un éditeur ; aucune statistique de parc du type « les clusters sont sur-provisionnés de N fois » ; aucun chiffre de performance, de surcoût ou de temps de convergence.
Le chiffre que cet article ne publiera pas
Une fourchette de sur-provisionnement moyen des clusters Kubernetes circule largement, et une version antérieure du brouillon de cet article la portait. Aucune page chargée le 2026-08-16 ne l’établit : ni la documentation Kubernetes, ni OpenCost, ni le dépôt VPA, ni le dépôt KRR, ni la FinOps Foundation ne publient de statistique de parc. Le remplacement n’est pas un autre chiffre, c’est une méthode — la requête PromQL plus bas. Un ratio de gaspillage est une propriété de votre cluster ; la seule valeur qui vous engage devant un comité est celle que vous avez relevée vous-même, à une date, sur une fenêtre que vous nommez.
La seule notion de gaspillage que cet article emploie vient du projet amont lui-même. La référence d’API de VPA définit le champ upperBound comme « Maximum recommended amount of resources. […] Any resources allocated beyond this value are likely wasted. » Elle est calculée sur vos pods, datée par la fenêtre du recommender, et publiée par le projet plutôt que par un vendeur d’optimisation.
Deux étages : KRR lit et explique, VPA lit et agit
C’est le point que la plupart des comparatifs manquent, et il commande tout le reste : les deux outils ne lisent pas la même source.
VPA lit metrics.k8s.io. La documentation Kubernetes écrit : « The VerticalPodAutoscaler requires a metrics source, such as Kubernetes’ Metrics Server add-on, to be installed in the cluster. The VPA components fetch metrics from the metrics.k8s.io API. » Le guide d’installation du dépôt est explicite sur le prérequis : « The metrics server must be deployed in your cluster. »
KRR lit Prometheus. Le dépôt publie : « It gathers pod usage data from Prometheus and recommends requests and limits for CPU and memory. » Prérequis publiés : Prometheus 2.26+, kube-state-metrics et cAdvisor, plus cinq métriques nommées.
VPA peut aussi lire Prometheus, mais ce n’est pas son défaut : le paramètre storage du recommender vaut checkpoint, valeurs supportées prometheus, checkpoint, avec prometheus-address à http://prometheus.monitoring.svc. En mode checkpoint, l’historique vit dans des objets VerticalPodAutoscalerCheckpoint du cluster.
La conséquence n’est pas « l’un est plus léger que l’autre ». KRR n’a rien à installer dans le cluster parce qu’il interroge une base de séries temporelles qui, elle, y est déjà. VPA installe trois composants parce qu’il doit agir. Lire et agir n’ont pas les mêmes prérequis.
Ces trois composants sont nommés par le dépôt : « The Vertical Pod Autoscaler consists of three parts. The recommender, updater and admission-controller. » Le recommender interroge l’utilisation et écrit quatre valeurs dans .status.recommendation.containerRecommendations[]. L’updater compare la demande courante à la recommandation et, selon le mode, évince le pod ou le redimensionne en place — « the updater respects PodDisruptionBudgets to minimize service impact ». L’admission controller est un webhook mutant qui applique la recommandation target aux pods à leur création.
| Champ | Définition publiée |
|---|---|
target |
Quantité recommandée, dans les bornes de la ContainerResourcePolicy |
lowerBound |
Minimum recommandé ; en dessous, « likely to have significant impact on performance/availability » |
upperBound |
Maximum recommandé ; au-delà, « any resources allocated beyond this value are likely wasted » |
uncappedTarget |
Cible calculée sans tenir compte de la ContainerResourcePolicy ; indication de statut uniquement |
L’écart entre uncappedTarget et target mesure combien votre resourcePolicy bride la recommandation. C’est l’indicateur que personne ne regarde, et il est gratuit.
Côté KRR, la frontière est nette et il faut la dire correctement. Le CLI est distribué sous licence MIT ; il n’écrit rien dans le cluster. L’application automatique des recommandations relève de KRR Enforcer, composant distinct présenté par le dépôt sous « Auto-Apply Mode ». Écrire que KRR redimensionne des pods est faux. La page de tarification de l’éditeur ne publie ni palier ni montant : elle propose un formulaire de devis.
Enfin, le dépôt KRR publie une section « Difference with Kubernetes VPA ». C’est un tableau écrit par l’un des deux outils comparés sur l’autre, et il se cite en nommant son auteur. Deux de ses cases appellent une correction. Sa ligne « Default History : 8 days (VPA) » est exacte pour la mémoire — memory-aggregation-interval 24h multiplié par memory-aggregation-interval-count 8 — mais sans objet pour le CPU, que VPA traite par histogramme à décroissance exponentielle et non par fenêtre. Sa ligne « Supports HPA : ❌ Not supported » côté VPA est contredite par la documentation de VPA elle-même, on y revient plus bas.
Les six modes de VPA, et le défaut qui évince
L’énumération publiée de l’API stable autoscaling.k8s.io/v1 est Enum: [Off Initial Recreate InPlaceOrRecreate InPlace Auto].
| Mode | État | Ce qui arrive au pod | Éviction |
|---|---|---|---|
Off |
stable | rien ; la recommandation est écrite dans .status. Publié : « This can be used for a “dry run”. » |
non |
Initial |
stable | appliqué à la création du pod uniquement, jamais pendant sa vie | non |
Recreate |
stable — valeur par défaut | « can update them during the lifetime of the pod by deleting and recreating the pod » | oui |
InPlaceOrRecreate |
GA depuis VPA 1.6.0, activé par défaut | tente en place ; « if in-place update fails, VPA will fall back to pod recreation » | oui, en repli |
InPlace |
alpha, VPA 1.7.0+ et Kubernetes 1.33+ | « will only attempt to update pods in-place and will never evict them » | jamais |
Auto |
déprécié depuis VPA 1.4.0 | alias de Recreate ; « Deprecated: This value is deprecated and will be removed in a future API version. » |
oui |
La ligne la plus importante est la troisième. La référence d’API publie, pour updateMode : « The default is ‘Recreate’. » Un objet VerticalPodAutoscaler écrit sans updatePolicy.updateMode évince des pods. Ce n’est pas un avis sur la prudence du projet, c’est la valeur par défaut publiée.
La chronologie ci-dessous vient des champs published_at de l’API GitHub des releases du dépôt kubernetes/autoscaler, pas des dates affichées par les pages HTML.
| Tag | Publié le | Ce qui change |
|---|---|---|
vertical-pod-autoscaler-1.4.0 |
2025-05-21 | in-place derrière la grille alpha InPlaceOrRecreate ; Auto déprécié |
vertical-pod-autoscaler-1.5.0 |
2025-09-23 | grille activée par défaut — le mode passe bêta |
vertical-pod-autoscaler-1.6.0 |
2026-02-12 | « Promote InPlaceOrRecreate feature to GA, defaulted to enabled » |
vertical-pod-autoscaler-1.7.0 |
2026-05-29 | mode InPlace ; grille InPlaceOrRecreate retirée ; --in-place-skip-disruption-budget passe bêta |
vertical-pod-autoscaler-1.7.1 |
2026-07-26 | dernier tag relevé |
Trois pages du même écosystème décrivent aujourd’hui ce mécanisme dans trois états différents, et aucune n’est fausse. Le fichier known-limitations.md du dépôt VPA ouvre toujours sa liste par « Whenever VPA updates the pod resources, the pod is recreated » — vrai pour Recreate et Auto, faux pour les deux modes en place. Le billet kubernetes.io du 2025-12-19 écrit que InPlaceOrRecreate « has graduated to beta » — exact à sa date, périmé depuis le 2026-02-12. Le fichier features.md, lui, porte le bloc FEATURE STATE complet : alpha en 1.4.0, bêta en 1.5.0, GA en 1.6.0.
La règle réutilisable de cet article
Un contenu qui décrit VPA sans nommer le mode décrit un comportement indéterminé. Un contenu qui décrit un état de fonctionnalité sans sa date décrit un instant. Sur ce sujet, une affirmation sans version et sans date ne vaut rien — y compris celle-ci, qui porte les deux. Preuve par l’exemple : le contrat de recherche de cette série, rédigé à partir du billet officiel de décembre 2025, énonçait « InPlaceOrRecreate : bêta ». C’était la lecture d’une source de premier niveau, et elle était périmée depuis six mois.
Le comportement observable est le produit de deux manifestes
Le resizePolicy ne vit pas dans l’objet VPA. Il vit dans la spécification du conteneur, donc dans le manifeste de charge.
apiVersion: apps/v1
kind: Deployment
metadata:
name: webshop-app
namespace: webshop-app
spec:
replicas: REPLACE_WITH_REPLICA_COUNT # ≥ 2 pour que l'updater agisse
selector:
matchLabels:
app: webshop-app
template:
metadata:
labels:
app: webshop-app
spec:
containers:
- name: app
image: REPLACE_WITH_IMAGE_REFERENCE
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired # défaut publié ; redimensionnement à chaud
- resourceName: memory
restartPolicy: RestartContainer # choix explicite
resources:
requests:
cpu: REPLACE_WITH_CPU_REQUEST
memory: REPLACE_WITH_MEMORY_REQUEST
limits:
memory: REPLACE_WITH_MEMORY_LIMIT
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: webshop-app
namespace: webshop-app
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: webshop-app
updatePolicy:
updateMode: "InPlaceOrRecreate" # toujours explicite — le défaut est Recreate
resourcePolicy:
containerPolicies:
- containerName: "app"
controlledValues: RequestsOnly # le défaut touche aussi les limits
controlledResources: ["cpu", "memory"]
minAllowed:
cpu: REPLACE_WITH_MIN_CPU
memory: REPLACE_WITH_MIN_MEMORY
maxAllowed:
cpu: REPLACE_WITH_MAX_CPU
memory: REPLACE_WITH_MAX_MEMORY
La documentation Kubernetes publie l’exemple exact de ce couplage, pour un conteneur en NotRequired sur le CPU et RestartContainer sur la mémoire : « If only CPU resources are changed, the container is resized in-place. If only memory resources are changed, the container is restarted. If both CPU and memory resources are changed simultaneously, the container is restarted (due to the memory policy). »
Deux fichiers, écrits dans la plupart des organisations par deux équipes différentes, et un comportement qui est le produit des deux. C’est là que le rightsizing casse — un ticket qui décrit ce que fait VPA sans nommer et le mode et le resizePolicy de la charge ne décrit rien d’exploitable.
controlledValues mérite le même soin. Valeur par défaut publiée : « The default is “RequestsAndLimits”. » Sa définition : « resource request and limits are scaled automatically. The limit is scaled proportionally to the request. » L’autre valeur, RequestsOnly, « only sets requests, leaving limits unchanged ». C’est la réponse précise à « pourquoi le rightsizing porte d’abord sur les requests », et elle n’est pas celle qu’on attend : le coût se pilote par les requests parce que c’est ce que l’ordonnanceur réserve, mais VPA, par défaut, ne s’y limite pas.
Petite dissonance de vocabulaire à connaître avant d’écrire un manifeste : le fichier features.md du dépôt VPA emploie resizePolicy: PreferNoRestart dans une note et NotRequired dans une autre. La valeur acceptée par l’API Kubernetes est NotRequired ; PreferNoRestart est le nom employé par le KEP de conception. Rien ne permet, à la lecture, d’en conclure à une divergence d’implémentation — mais dans un YAML, seul NotRequired passe.
Le redimensionnement en place est stable — et fortement borné
Le redimensionnement en place des ressources de conteneur (in-place resize) est stable et activé par défaut en Kubernetes v1.35 ; il était bêta en v1.33 et alpha en v1.27. La documentation de la version 1.36 publie une liste de limites qu’il faut lire avant de bâtir un plan dessus.
| Limite | Formulation publiée |
|---|---|
| Ressources | « Only CPU and memory resources can be resized. » |
| Baisse de mémoire | si l’usage dépasse la limite demandée, « the resize will be skipped and the status will remain in an “In Progress” state » |
| Classe QoS | déterminée à la création et « cannot be changed by a resize » |
| Conteneurs | init non redémarrables et éphémères exclus ; « Sidecar containers can be resized. » |
| Retrait | « Resource requests and limits cannot be entirely removed once set; they can only be changed to different values. » |
| Système | « Windows pods do not support in-place resize. » |
| Nœud | pods sous politique statique de CPU ou de gestionnaire de mémoire exclus ; contrainte publiée aussi sur le swap |
restartPolicy |
« If a Pod’s overall restartPolicy is Never, then any container resizePolicy must be NotRequired for all resources. » |
| Client | « The --subresource resize command line argument requires kubectl client version v1.32.0 or later. » |
Deux faits de cette page méritent d’être sortis du tableau, parce qu’ils cassent des plans entiers.
L’ordonnanceur retient le maximum pendant un redimensionnement en attente : « the scheduler uses the maximum of a container’s desired requests, allocated requests, and actual requests from the status when making scheduling decisions ». Autrement dit, baisser une request ne libère rien pour l’ordonnanceur tant que le redimensionnement n’est pas terminé. Un plan qui enchaîne « je baisse, donc je retire un nœud » se heurte à des pods non ordonnançables.
Les runtimes ne suivent pas toujours. Le billet d’annonce du passage en stable l’écrit sans détour : « Java and Python runtimes do not support resizing memory without restart. » Le même billet conserve une réserve que le lecteur doit avoir en tête pour un mécanisme déclaré stable : « There are known race conditions between the kubelet and scheduler with regards to in-place pod resize. Work is underway to resolve these issues over the next few releases. »
Une trajectoire à surveiller, enfin. Le redimensionnement en place des ressources de niveau pod (.spec.resources) est passé bêta, activé par défaut, en Kubernetes 1.36, derrière la grille InPlacePodLevelResourcesVerticalScaling. Or le README du dépôt VPA publie un avertissement IMPORTANT : « At the moment, VPA is not compatible with workloads that define pod-level resources stanzas », avec deux modes d’échec précis à la création du pod. Deux trajectoires qui se croisent, et un travail de compatibilité annoncé par la formule « Work has started » — sans version cible. Sur 1.36, n’activez pas VPA sur une charge qui déclare .spec.resources, et ne pariez pas sur une date.
Mesurer votre ratio, puis choisir un mode par namespace
Aucune des phases qui suivent n’a été exécutée. Ce sont des commandes réelles, avec leurs options publiées, dans un ordre construit à partir des mécanismes documentés ; les sorties sont des résultats attendus, pas des relevés.
Phase 0 — établir le plancher. Quatre vérifications, chacune adossée à un prérequis publié.
# 1 — serveur : ≥ 1.35 pour un redimensionnement en place stable
kubectl version -o json | jq -r '.serverVersion.gitVersion'
# 2 — client : ≥ v1.32.0 pour le drapeau --subresource resize
kubectl version --client -o json | jq -r '.clientVersion.gitVersion'
# 3 — source de métriques de VPA
kubectl get apiservices v1beta1.metrics.k8s.io \
-o jsonpath='{.status.conditions[?(@.type=="Available")].status}'
# 4 — prérequis de KRR
kubectl get pods -A -l app.kubernetes.io/name=prometheus
kubectl get pods -A -l app.kubernetes.io/name=kube-state-metrics
Phase 1 — obtenir son propre ratio, sans rien changer. Les noms de métriques sont documentés : kube_pod_container_resource_requests est marqué STABLE par kube-state-metrics, container_cpu_usage_seconds_total et container_memory_working_set_bytes sont publiés comme métriques d’entrée par KRR. L’assemblage ci-dessous est le nôtre, il n’a été exécuté sur aucun cluster, et les jeux d’étiquettes (job, metrics_path, container) dépendent de votre configuration de collecte : à valider sur votre plateforme avant d’en tirer une décision.
# Ratio requested/used CPU, par namespace, sur 7 jours.
avg_over_time(
sum by (namespace) (
kube_pod_container_resource_requests{resource="cpu", container!="", container!="POD"}
)[7d:5m]
)
/
avg_over_time(
sum by (namespace) (
rate(container_cpu_usage_seconds_total{container!="", container!="POD"}[5m])
)[7d:5m]
)
# Ratio requested/used mémoire, par namespace, sur 7 jours.
# Le dénominateur retient le MAXIMUM : une réservation mémoire doit couvrir le pic.
sum by (namespace) (
kube_pod_container_resource_requests{resource="memory", container!="", container!="POD"}
)
/
max_over_time(
sum by (namespace) (
container_memory_working_set_bytes{container!="", container!="POD"}
)[7d:5m]
)
kube-state-metrics publie sa propre réserve sur la métrique du numérateur : « It is recommended to use the kube_pod_resource_request metric exposed by kube-scheduler instead, as it is more precise. » La requête ci-dessus fonctionne avec la pile la plus répandue ; la variante plus précise existe.
Trois façons de mal lire ces deux nombres, à écrire noir sur blanc. Un ratio CPU élevé sur une charge en rafale n’est pas du gaspillage, c’est une réserve de rafale — la moyenne ne dit rien du percentile. Un ratio mémoire proche de 1 n’est pas une victoire, c’est une charge à un OOM près. Et un ratio agrégé par namespace masque le conteneur unique responsable de tout l’écart : descendez à by (namespace, container) avant de décider.
Phase 2 — les deux modèles de recommandation, cités comme défauts d’outil. La stratégie simple de KRR est publiée ainsi : « For CPU, we set a request at the 95th percentile with no limit » et « For memory, we take the maximum value over the past week and add a 15% buffer ». Le recommender de VPA publie, lui, target-cpu-percentile et target-memory-percentile à 0.9, recommendation-margin-fraction à 0.15, des bornes à 0.5 et 0.95, une agrégation mémoire de 24h sur 8 intervalles, et un cpu-histogram-decay-half-life de 24h. Ce sont des paramètres d’outils, pas des règles d’ingénierie.
La comparaison honnête ne porte pas sur les nombres mais sur la forme du calcul. KRR calcule le CPU par percentile sur une fenêtre fixe ; VPA le calcule par histogramme à décroissance exponentielle. Un histogramme à demi-vie n’a pas de fenêtre : un échantillon de la semaine dernière pèse encore, mais peu. C’est un modèle différent, pas un réglage différent — et cela suffit à expliquer un écart entre les deux recommandations sans que l’une soit en tort.
Phase 3 — appliquer par vagues. La séquence ci-dessous est une proposition de travail, adossée à des mécanismes publiés mais pas à une exécution. Trois namespaces, trois profils : webshop-web élastique et déjà sous HPA CPU, webshop-app stable, webshop-db dominé par la mémoire et hostile aux redémarrages.
| Vague | Namespace | Mode | controlledValues |
Pourquoi |
|---|---|---|---|---|
| 1 | webshop-app |
Initial |
RequestsOnly |
on n’agit qu’à la création ; aucun pod vivant n’est touché |
| 2 | webshop-app |
InPlaceOrRecreate |
RequestsOnly |
mode GA depuis VPA 1.6.0 ; resizePolicy CPU NotRequired, mémoire RestartContainer |
| 3 | webshop-web |
InPlaceOrRecreate, controlledResources: ["memory"] |
RequestsOnly |
HPA est déjà sur le CPU, VPA ne doit pas y toucher |
| 4 | webshop-db |
Off, puis décision humaine |
— | la baisse de mémoire en place est en meilleur effort et le runtime peut ne pas la supporter |
Sur VKS, le prérequis facile n’est pas celui qu’on croit. Les notes de version publient la liste des paquets livrés automatiquement avec un cluster, et metrics-server en fait partie ; Prometheus, lui, figure dans la liste des paquets « can be optionally installed ». Le prérequis de VPA est donc déjà là, celui de KRR est à poser — l’inverse de l’intuition « l’outil qui ne s’installe pas dans le cluster est le plus facile à essayer ». Le socle correspondant est décrit dans Prometheus et Grafana sur VKS en production, et le plancher de version dépend du VKr et non de VCF : les VKr publiés vont jusqu’à 1.36.1 (18-Jun-2026), et la montée de version est le sujet de Day-2 Ops VKS : lifecycle et upgrades.
Deux trous à dire à voix haute ici. Aucune page Broadcom chargée ne nomme Vertical Pod Autoscaler, KRR ou un outil de rightsizing tiers : la page d’autoscaling VKS ne documente que le Cluster Autoscaler. VPA sur VKS se traite donc comme un CRD sur un cluster Kubernetes conforme — c’est une reconstitution de notre part, pas un chemin documenté par l’éditeur. Et aucune page ne publie la version de kubectl attendue côté client pour un cluster VKS, alors que --subresource resize en exige une : c’est la vérification 2 de la phase 0, à relever sur votre instance. Le prérequis de plateforme lui-même est traité dans Premier cluster VKS sur VCF 9.
Pièges & points de vigilance
Le VPA sans mode évince, et le mode par défaut déplace vos limits
Les deux pièges les plus coûteux tiennent dans deux valeurs par défaut publiées. updateMode vaut Recreate : un objet VPA posé « pour voir » supprime et recrée des pods dès que la recommandation s’écarte. controlledValues vaut RequestsAndLimits : baisser une request de moitié baisse la limit dans le même rapport, ce qui crée un risque d’OOM au moment précis où l’on croit ne libérer que de la réservation. Écrivez les deux champs explicitement, sur chaque objet.
- Le mono-réplica n’est jamais mis à jour. Le paramètre
min-replicasde l’updater vaut2— « Minimum number of replicas to perform update ». Une charge à une réplique reçoit des recommandations dans.statuset ne les voit jamais appliquées. Avant de conclure « VPA ne fait rien », comptez les répliques. - La baisse de mémoire est silencieusement sautée. Ni erreur, ni événement d’échec : la condition
PodResizeInProgressreste ouverte. Surveillez-la comme une alerte, pas comme un état transitoire. Et côté VPA, « memory limit downscaling is not supported for pods withresizePolicy: PreferNoRestart[…] VPA will fall back to pod recreation » — la charge que vous vouliez ne pas redémarrer redémarre, par le chemin de repli. - La classe QoS ne change pas. Elle est déterminée à la création et immuable. Un rightsizing qui « aligne requests et limits pour passer en
Guaranteed» ne peut pas se faire à chaud : c’est une recréation, à planifier comme telle. VPA publie d’ailleurs le changement de classe QoS parmi ses cinq conditions de repli, avec le report de plus de 5 minutes, l’exécution de plus d’1 heure, l’infaisabilité et la baisse de limite mémoire. - VPA et HPA : citer la moitié de la phrase ferme une porte ouverte. Le texte publié est « Vertical Pod Autoscaler should not be used with the Horizontal Pod Autoscaler (HPA) on the same resource metric (CPU or memory) at this moment. However, you can use VPA with HPA on separate resource metrics (e.g. VPA on memory and HPA on CPU) as well as with HPA on custom and external metrics. » La formule courante « VPA et HPA sont incompatibles » est une troncature, et c’est exactement le cas de
webshop-web. - Plusieurs objets VPA sur le même pod, c’est indéfini. Le dépôt écrit « Multiple VPA resources matching the same pod have undefined behavior. » Inventoriez les sélecteurs avant tout diagnostic de recommandation instable. Dans le même registre : VPA « does not update resources of pods which are not run under a controller » — une charge lancée en pod nu ne recevra jamais de recommandation appliquée.
- KRR se dégrade sans le dire. Sans
kube_replicaset_owner,kube_pod_owneretkube_pod_status_phase, « it will only consider currently-running pods when calculating recommendations » — la recommandation est calculée sur un échantillon amputé, et l’outil ne signale pas cette dégradation en erreur. - Une limite posée ne se retire plus. « Resource requests and limits cannot be entirely removed once set; they can only be changed to different values. » Un rightsizing qui ajoute une
limitlà où il n’y en avait pas est irréversible au sens strict : cela se décide avant, pas après. Les sorties disponibles sont le passage enupdateMode: "Off", le retour aux valeurs antérieures dans le manifeste, ou unkubectl patch --subresource resizesur un pod donné. - Le chemin d’installation publié reste le script. Un graphe Helm officiel existe (
vertical-pod-autoscaler-chart-0.11.0, publié le 2026-07-26), mais la page d’installation du dépôt documente./hack/vpa-up.shet ne le mentionne pas. Le tag existe ; le chemin documenté est l’autre.
Conclusion
Le rightsizing n’est pas un réglage, c’est une chaîne de décisions écrites : un mode nommé, un controlledValues assumé, un resizePolicy cohérent avec le runtime, et un ratio relevé sur votre cluster plutôt que récité. Chacun de ces quatre points a une valeur par défaut, et aucune de ces valeurs par défaut n’est neutre.
Il reste une frontière, et c’est celle qui ouvre l’article suivant. Le rightsizing ne produit pas d’économie. Il libère de la capacité — des cœurs et des octets qui ne sont plus réservés. Cette capacité ne devient de l’argent que si un nœud est retiré, si un nœud prévu n’est pas acheté, ou si une autre charge la consomme au lieu d’en réclamer de la nouvelle. Dans les trois cas, la décision est humaine et elle appartient à quelqu’un d’autre que l’exploitant Kubernetes — c’est aussi ce qui décide qui reçoit la recommandation et qui l’applique, un modèle de délégation traité dans VCF 9.1 : Kubernetes en self-service.
Deux étages, pas deux rivaux
KRR lit Prometheus depuis l’extérieur et explique ; VPA lit metrics.k8s.io depuis l’intérieur et agit. L’application côté KRR est un composant distinct, KRR Enforcer.
Deux défauts à écrire à la main
updateMode vaut Recreate et controlledValues vaut RequestsAndLimits. Un objet VPA qui laisse ces deux champs vides est une décision non prise.
Votre ratio, pas une moyenne
Deux requêtes PromQL, un ratio par namespace puis par conteneur, une date et une fenêtre nommées. C’est le seul chiffre de gaspillage qui vous engage devant un comité.
Dans la série FinOps cloud native
Article précédent : OpenCost : voir avant d’agir sur les coûts K8s. Suite : Modèles de coûts FinOps : ce que facturent vraiment AWS, Azure, GCP et VCF, qui reprend là où celui-ci s’arrête — la capacité libérée devient-elle une dépense évitée, et selon quel modèle.
Reçois le prochain par email
Les nouveaux articles et séries, envoyés à leur publication. Aucun autre courrier.



