Aller au contenu
Edouard Topin's Blog
FinOps cloud native / Série 02/03

Rightsizing Kubernetes avec VPA et KRR

VPA recommande et applique, KRR recommande et explique. Les six modes de VPA, et ce que chacun fait vraiment au pod depuis que le redimensionnement en place est stable.

Edouard Topin
20 min de lecture
Illustration éditoriale abstraite d'un conteneur surdimensionné se rétractant pour épouser un contour plus serré.

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_*.

Kubernetes 1.35 → 1.36VPA 1.7.1Aucun lab exécuté

TL;DR

  • La décision : écrire updateMode explicitement sur chaque objet VerticalPodAutoscaler, y compris quand la réponse est Off. 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 : controlledValues vaut RequestsAndLimits par 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 la limit mé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/used par 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.

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émoirememory-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.

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 mono-réplica n’est jamais mis à jour. Le paramètre min-replicas de l’updater vaut 2 — « Minimum number of replicas to perform update ». Une charge à une réplique reçoit des recommandations dans .status et 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 PodResizeInProgress reste ouverte. Surveillez-la comme une alerte, pas comme un état transitoire. Et côté VPA, « memory limit downscaling is not supported for pods with resizePolicy: 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_owner et kube_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 limit là 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 en updateMode: "Off", le retour aux valeurs antérieures dans le manifeste, ou un kubectl patch --subresource resize sur 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.sh et 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é.

Reçois le prochain par email

Les nouveaux articles et séries, envoyés à leur publication. Aucun autre courrier.

Désabonnement en un clic, à tout moment.

Retour au blog
Partager

Articles similaires

  1. 17 min de lecture

    Modèles de coûts FinOps : ce que facturent AWS, Azure et GCP — et ce que VCF calcule

    Un cluster-heure EKS, un palier AKS, une requête de pod GKE et un matériel VCF amorti ne sont pas quatre valeurs de la même variable. Ce que chaque plateforme facture, et ce que VCF calcule.

  2. 17 min de lecture

    OpenCost : voir avant d'agir sur les coûts K8s

    OpenCost rend le coût d'un cluster lisible par namespace. On regarde son modèle d'allocation, ce que son prix par défaut vaut vraiment, et où s'arrête l'open source.

  3. 23 min de lecture

    Network policies et Cilium : construire un default-deny défendable

    L'API NetworkPolicy est livrée avec Kubernetes ; l'appliquer est le travail du CNI. Ce que Cilium ajoute, ce qui reste standard, et comment atteindre le default-deny sans casser la production.

Suivre le blog

Nouveaux articles, réflexions et mises à jour.