Pourquoi vos Clusters Kubernetes Coûtent Trop Cher
Soyons honnêtes : si vous gérez des clusters Kubernetes en production, il y a de fortes chances que vous payiez 30 à 40 % de trop. Et non, ce n'est pas une exagération pour faire du sensationnalisme. Les chiffres de 2026 sont assez clairs — plus de 68 % des organisations surpaient leurs déploiements Kubernetes, principalement à cause de mauvaises configurations et d'un manque de suivi continu.
Le problème, au fond, est structurel.
Kubernetes facilite le déploiement et le scaling des applications, mais il ne fait absolument rien pour optimiser les coûts de lui-même. Par défaut, les développeurs demandent plus de ressources que nécessaire « au cas où » (on a tous fait ça), le scheduler réserve ces ressources même si elles ne sont jamais utilisées, et les nœuds tournent à 20-30 % d'utilisation réelle. Résultat : des factures cloud qui explosent sans que personne ne comprenne vraiment pourquoi.
La bonne nouvelle, c'est qu'en 2026 l'écosystème d'outils a considérablement mûri. Entre le Vertical Pod Autoscaler, Karpenter, les instances Spot et les mécanismes de gouvernance natifs, il est tout à fait réaliste de réduire votre facture Kubernetes de 40 à 50 %. Sans sacrifier la performance ni la fiabilité. Ce guide vous montre comment, étape par étape.
Le Sur-Provisionnement : le Premier Poste de Gaspillage
Avant de parler d'outils, il faut comprendre pourquoi Kubernetes coûte si cher. La réponse tient en deux mots : requests et limits.
En Kubernetes, chaque conteneur déclare ses besoins en CPU et mémoire via deux paramètres. Les requests définissent le minimum garanti — c'est sur cette base que le scheduler place les pods sur les nœuds. Les limits définissent le maximum autorisé. Jusque-là, tout va bien.
Le problème ? Le scheduling repose sur les ressources demandées, pas sur la consommation réelle.
En pratique, les audits révèlent que 80 à 90 % des pods ont des requests CPU et mémoire largement gonflées. En moyenne, seulement 13 % du CPU demandé est réellement utilisé. Autrement dit, pour chaque euro dépensé en compute Kubernetes, 87 centimes sont gaspillés en CPU réservé mais inactif. Ça fait mal quand on pose les chiffres comme ça.
Prenons un exemple concret. Une équipe configure ses pods avec 2 vCPU de request, mais l'utilisation réelle oscille autour de 0,2 vCPU. Chaque pod est sur-provisionné d'un facteur 10. Sur un cluster de 200 pods dans cette situation, ça force la création de nœuds supplémentaires et ajoute des milliers d'euros à la facture mensuelle — pour strictement rien.
Comment Détecter le Sur-Provisionnement
La première étape, c'est de mesurer l'écart entre ce qui est demandé et ce qui est réellement consommé. Voici une requête PromQL à exécuter sur votre instance Prometheus :
# Ratio d'utilisation CPU réelle vs requests par namespace
# Valeur sous 0.5 = sur-provisionnement significatif
sum(rate(container_cpu_usage_seconds_total{container!=""}[5m])) by (namespace)
/
sum(kube_pod_container_resource_requests{resource="cpu"}) by (namespace)
# Ratio d'utilisation mémoire réelle vs requests par namespace
sum(container_memory_working_set_bytes{container!=""}) by (namespace)
/
sum(kube_pod_container_resource_requests{resource="memory"}) by (namespace)
Si le ratio est inférieur à 0,5 pour un namespace, vous avez un candidat évident au right-sizing. En dessous de 0,3, c'est du gaspillage massif qui mérite une action immédiate.
Right-Sizing avec le Vertical Pod Autoscaler (VPA)
Le Vertical Pod Autoscaler est l'outil natif de Kubernetes pour résoudre ce problème de sur-provisionnement. Il analyse l'utilisation réelle des ressources sur plusieurs jours et ajuste automatiquement les requests et limits de vos conteneurs.
Avec Kubernetes 1.35 en 2026, le VPA est devenu franchement plus fiable et précis qu'il ne l'était il y a encore deux ans. Il propose trois modes :
- Off (Recommandation) — Le VPA calcule les valeurs optimales et les affiche, sans rien modifier. Idéal pour commencer en douceur et valider les recommandations avant d'y toucher.
- Auto — Le VPA met à jour automatiquement les requests et limits des pods. Attention cependant : cela implique un redémarrage des pods lors des ajustements.
- Initial — Le VPA applique les recommandations uniquement à la création des pods, sans modifier les pods existants. Un bon compromis.
Déployer le VPA en Mode Recommandation
Commencez toujours par le mode recommandation. Toujours. Évaluez l'impact avant d'activer les modifications automatiques :
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: api-backend-vpa
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api-backend
updatePolicy:
updateMode: "Off" # Mode recommandation uniquement
resourcePolicy:
containerPolicies:
- containerName: api
minAllowed:
cpu: "50m"
memory: "64Mi"
maxAllowed:
cpu: "2000m"
memory: "4Gi"
controlledResources: ["cpu", "memory"]
Après quelques jours de collecte (comptez 3 à 5 jours pour des données fiables), consultez les recommandations :
kubectl describe vpa api-backend-vpa -n production
# Sortie typique :
# Recommendation:
# Container Recommendations:
# Container Name: api
# Lower Bound: Cpu: 25m, Memory: 128Mi
# Target: Cpu: 100m, Memory: 256Mi
# Upper Bound: Cpu: 400m, Memory: 512Mi
Si vos requests actuelles sont de 500m CPU et 1Gi de mémoire, et que le VPA recommande 100m CPU et 256Mi, vous pouvez réduire vos requests de 80 %. Multipliez ça par des centaines de pods et… les économies parlent d'elles-mêmes.
Goldilocks : Visualiser les Recommandations VPA
L'outil open-source Goldilocks (par Fairwinds) ajoute une interface web aux recommandations VPA. C'est franchement l'un des meilleurs moyens de rendre le right-sizing accessible à toute l'équipe. Il crée automatiquement un VPA en mode recommandation pour chaque déploiement d'un namespace labellisé, puis affiche un dashboard clair avec les valeurs actuelles vs recommandées :
# Installer Goldilocks via Helm
helm install goldilocks fairwinds-stable/goldilocks --namespace goldilocks --create-namespace
# Activer Goldilocks sur un namespace
kubectl label namespace production goldilocks.fairwinds.com/enabled=true
# Accéder au dashboard
kubectl port-forward -n goldilocks svc/goldilocks-dashboard 8080:80
Goldilocks montre immédiatement quels déploiements sont les plus sur-provisionnés et quantifie les économies potentielles. C'est un excellent point de départ pour convaincre votre équipe (ou votre management) d'investir du temps dans le right-sizing.
Autoscaling Horizontal : HPA et KEDA
Le VPA ajuste les ressources par pod, mais le Horizontal Pod Autoscaler (HPA) ajuste le nombre de pods en fonction de la charge. Les deux sont complémentaires — mais attention, il faut éviter de les utiliser sur les mêmes métriques pour un même déploiement. Sinon ils entrent en conflit et c'est le chaos.
En 2026, le HPA de Kubernetes 1.35 inclut des niveaux de tolérance configurables. Avant, le HPA utilisait une tolérance fixe de 10 % — un changement d'utilisation inférieur à 10 % ne déclenchait pas de scaling. On peut désormais ajuster ce seuil, ce qui a réduit les événements de scaling inutiles de 25 % dans les benchmarks récents. Un vrai progrès.
HPA avec Politiques de Scaling Optimisées
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-backend-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-backend
minReplicas: 2
maxReplicas: 20
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # Attendre 5 min avant scale-down
policies:
- type: Percent
value: 25 # Max 25% de réduction par intervalle
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Percent
value: 50 # Max 50% d'augmentation par intervalle
periodSeconds: 60
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 75
La clé pour les économies, c'est la section scaleDown. Sans configuration bien pensée du scale-down, le HPA scale up rapidement mais met une éternité à scale down — et ce sont justement ces pods excédentaires qui gonflent la facture.
KEDA pour les Workloads Événementiels
KEDA (Kubernetes Event-Driven Autoscaling) étend le HPA en permettant le scaling basé sur des sources d'événements externes : files de messages (SQS, Kafka, RabbitMQ), métriques Prometheus, requêtes HTTP en attente, et bien d'autres.
Son avantage majeur pour les coûts ? KEDA peut scaler à zéro. Là où le HPA nécessite au minimum un replica, KEDA peut tout simplement éteindre les pods quand il n'y a rien à traiter.
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: worker-scaledobject
namespace: production
spec:
scaleTargetRef:
name: queue-worker
minReplicaCount: 0 # Scale à zéro quand la file est vide
maxReplicaCount: 50
cooldownPeriod: 300
triggers:
- type: aws-sqs-queue
metadata:
queueURL: https://sqs.eu-west-1.amazonaws.com/123456789/processing-queue
queueLength: "5" # 1 pod par 5 messages en file
awsRegion: eu-west-1
authenticationRef:
name: aws-credentials
Pour les workloads batch ou événementiels, la différence est radicale. Un worker qui tourne 24h/24 « au cas où » vs un worker qui scale à zéro et ne consomme rien quand la file est vide — sur la facture mensuelle, ça se voit immédiatement.
Karpenter : l'Autoscaler de Nœuds Nouvelle Génération
Le right-sizing des pods, c'est essentiel. Mais si les nœuds sous-jacents ne sont pas optimisés, vous payez toujours trop. C'est là qu'intervient Karpenter.
Le problème avec le Cluster Autoscaler classique : il travaille avec des Node Groups prédéfinis (les Auto Scaling Groups chez AWS). Si votre pod a besoin de 3 vCPU et que votre groupe ne contient que des instances à 8 vCPU, vous payez pour 5 vCPU de vide. Pas très malin.
Karpenter ne fonctionne pas du tout comme ça. Il analyse les pods en attente et provisionne directement l'instance exacte correspondant au besoin, au meilleur prix, en quelques secondes. Plus de groupes de nœuds rigides, plus de gaspillage lié au bin-packing approximatif.
En 2026, Karpenter v1 GA est stable en production. Salesforce a migré plus de 1 000 clusters vers Karpenter — ce n'est plus un outil expérimental. Les résultats typiques : 30 à 50 % de réduction des coûts par rapport aux node groups statiques, provisionnement 70 % plus rapide, et 20 % de réduction de l'overhead CPU/mémoire.
Configuration Karpenter avec Instances Spot
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: general-workloads
spec:
template:
spec:
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64", "arm64"] # Accepter Graviton pour -20% de coût
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"] # Spot en priorité
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"] # Familles compute, general, memory
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["5"] # Générations récentes uniquement
nodeClassRef:
group: karpenter.k8s.aws/v1
kind: EC2NodeClass
name: default
limits:
cpu: "1000" # Max 1000 vCPU pour ce NodePool
memory: "2000Gi" # Max 2000 Gi de mémoire
disruption:
consolidationPolicy: WhenUnderutilized # Consolider les nœuds sous-utilisés
consolidateAfter: 60s
---
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: default
spec:
role: "KarpenterNodeRole-mon-cluster"
amiSelectorTerms:
- alias: "al2023@latest"
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: "mon-cluster"
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: "mon-cluster"
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 50Gi
volumeType: gp3
encrypted: true
Quelques points importants dans cette configuration :
- Architecture arm64 incluse — Les instances Graviton coûtent environ 20 % de moins à performance équivalente. En laissant Karpenter choisir entre amd64 et arm64, vous maximisez les économies (à condition que vos images soient multi-arch, bien sûr).
- Spot en priorité — Karpenter essaie d'abord les instances Spot (60 à 90 % moins chères) avant de se rabattre sur du on-demand.
- Consolidation automatique — Quand les workloads diminuent, Karpenter remplace les nœuds sous-utilisés par des instances plus petites. Honnêtement, c'est cette fonctionnalité qui fait la vraie différence sur la facture.
- Limites de ressources — Le garde-fou essentiel pour éviter qu'un bug de scaling provisionne des centaines de nœuds (et oui, ça arrive).
Gouvernance des Coûts par Namespace
L'optimisation technique, c'est bien. Mais ça ne suffit pas si n'importe quelle équipe peut déployer n'importe quoi sans contrainte. Kubernetes fournit deux mécanismes natifs pour poser des garde-fous financiers : ResourceQuota et LimitRange.
ResourceQuota : le Budget par Namespace
Un ResourceQuota agit comme un budget pour un namespace. Il fixe des limites absolues sur les ressources totales consommables. Si un déploiement tente de dépasser le quota, Kubernetes rejette la requête avec une erreur 403. Simple et efficace.
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-backend-quota
namespace: team-backend
spec:
hard:
requests.cpu: "20" # Max 20 vCPU de requests cumulées
requests.memory: "40Gi" # Max 40 Gi de mémoire requests
limits.cpu: "40" # Max 40 vCPU de limits cumulées
limits.memory: "80Gi" # Max 80 Gi de mémoire limits
pods: "100" # Max 100 pods dans ce namespace
persistentvolumeclaims: "20" # Max 20 PVC
LimitRange : les Contraintes par Pod
Le LimitRange complète le ResourceQuota en fixant des valeurs par défaut et des bornes pour chaque conteneur individuel. C'est la protection contre le développeur qui oublie (ou qui ne pense pas) à spécifier ses requests :
apiVersion: v1
kind: LimitRange
metadata:
name: team-backend-limits
namespace: team-backend
spec:
limits:
- type: Container
default: # Valeurs par défaut si non spécifiées
cpu: "200m"
memory: "256Mi"
defaultRequest: # Requests par défaut
cpu: "100m"
memory: "128Mi"
max: # Maximum autorisé par conteneur
cpu: "4"
memory: "8Gi"
min: # Minimum autorisé
cpu: "10m"
memory: "16Mi"
maxLimitRequestRatio: # Ratio max limit/request
cpu: "4" # La limit ne peut pas dépasser 4x la request
memory: "4"
Le paramètre maxLimitRequestRatio est particulièrement important pour les coûts. Sans cette contrainte, un développeur peut très bien configurer une request de 10m CPU avec une limit de 2 CPU — le scheduler place le pod sur un petit nœud, mais le pod peut ensuite consommer bien plus que prévu, perturbant les autres workloads et faussant complètement le bin-packing.
Monitoring des Quotas avec Prometheus
Mettez en place des alertes quand les namespaces approchent de leurs quotas. Mieux vaut anticiper que découvrir un déploiement bloqué un vendredi soir :
# Alerte Prometheus : namespace utilisant plus de 80% de son quota CPU
groups:
- name: quota-alerts
rules:
- alert: NamespaceQuotaCPUHigh
expr: |
(
kube_resourcequota{type="used", resource="requests.cpu"}
/
kube_resourcequota{type="hard", resource="requests.cpu"}
) * 100 > 80
for: 10m
labels:
severity: warning
annotations:
summary: "Namespace {{ $labels.namespace }} utilise {{ $value | printf \"%.0f\" }}% de son quota CPU"
description: "Le namespace approche de sa limite. Envisagez le right-sizing ou une augmentation du quota."
Réduire les Coûts Réseau avec le Topology Aware Routing
Un poste de dépense souvent ignoré en Kubernetes : le trafic réseau inter-zones. Par défaut, quand un service A appelle un service B, Kubernetes ne tient pas compte de la zone de disponibilité. Le trafic peut traverser des zones (par exemple eu-west-1a vers eu-west-1b), et chaque traversée est facturée entre 0,01 et 0,02 $ par Go chez AWS.
Sur des applications à fort trafic, ça représente des milliers d'euros par mois. Pour du trafic qui aurait pu rester dans la même zone.
Le Topology Aware Routing, fonctionnalité native de Kubernetes, résout ce problème en routant le trafic vers les pods de la même zone en priorité :
apiVersion: v1
kind: Service
metadata:
name: api-backend
namespace: production
annotations:
service.kubernetes.io/topology-mode: Auto
spec:
selector:
app: api-backend
ports:
- port: 80
targetPort: 8080
Un simple ajout d'annotation. C'est tout. En pratique, cette configuration réduit les coûts de transfert inter-zones de 60 à 80 % pour les services à fort volume d'appels internes. Honnêtement, c'est probablement l'optimisation avec le meilleur ratio effort/impact de tout ce guide.
Observabilité des Coûts avec Kubecost
Kubecost (désormais une entreprise IBM) est la solution de référence pour la visibilité des coûts Kubernetes. Il attribue un coût réel à chaque namespace, déploiement et pod en corrélant les données de facturation cloud avec les métriques de consommation Kubernetes.
L'installation via Helm est rapide :
# Installer Kubecost sur votre cluster
helm install kubecost cost-analyzer --repo https://kubecost.github.io/cost-analyzer/ --namespace kubecost --create-namespace --set kubecostToken="votre-token" --set prometheus.server.enabled=true
# Accéder au dashboard
kubectl port-forward -n kubecost svc/kubecost-cost-analyzer 9090:9090
Kubecost fournit des recommandations concrètes : quels déploiements sont sur-provisionnés, quels namespaces dépensent le plus, et surtout combien vous économiseriez en appliquant le right-sizing recommandé. Les organisations rapportent typiquement 20 à 30 % d'économies dès le premier mois d'utilisation active. Ce n'est pas négligeable.
Pour un chargeback efficace, combinez Kubecost avec un système de labels rigoureux. Chaque déploiement devrait porter au minimum ces labels :
metadata:
labels:
app.kubernetes.io/name: api-backend
app.kubernetes.io/team: backend-team
app.kubernetes.io/env: production
app.kubernetes.io/cost-center: cc-1234
Sans labels cohérents, Kubecost ne peut pas attribuer correctement les coûts aux bonnes équipes. Et sans attribution claire, personne ne se sent responsable de ses dépenses.
Stratégie Globale : le Plan d'Action en 5 Étapes
Voici l'ordre que je recommande pour maximiser le retour sur investissement de votre optimisation Kubernetes :
- Semaine 1-2 : Mesurer — Déployez Kubecost et le VPA en mode recommandation sur tous les namespaces. Identifiez les 10 déploiements les plus sur-provisionnés. Pas d'action corrective à ce stade, juste de la collecte de données.
- Semaine 3-4 : Right-sizer — Appliquez les recommandations VPA sur les déploiements identifiés. C'est le quick win : réduction attendue de 20 à 30 %.
- Mois 2 : Autoscaler — Migrez du Cluster Autoscaler vers Karpenter. Activez les instances Spot et Graviton. Réduction supplémentaire de 15 à 25 %.
- Mois 3 : Gouverner — Déployez ResourceQuotas et LimitRanges par namespace. Implémentez les alertes Prometheus sur les quotas. C'est moins spectaculaire, mais ça empêche les régressions.
- En continu : Itérer — Revue hebdomadaire des dashboards Kubecost, revue trimestrielle approfondie des tendances de coûts et ajustement des engagements.
Cette approche progressive permet de montrer des résultats rapides (le right-sizing seul donne déjà 20-30 % d'économies) tout en construisant une gouvernance durable. Les équipes les plus disciplinées atteignent 40 à 70 % de réduction globale en suivant ce plan sur un trimestre.
FAQ
Quel est le seuil de dépense à partir duquel l'optimisation Kubernetes vaut l'investissement ?
Le point d'inflexion se situe généralement autour de 10 000 à 20 000 € de dépense mensuelle, soit environ 20-50 nœuds ou 100-200 pods. En dessous, les gains absolus risquent de ne pas justifier le temps investi dans la mise en place des outils. Au-dessus, chaque pourcentage de réduction représente des centaines voire des milliers d'euros d'économies mensuelles — et là, ça vaut clairement le coup.
Peut-on utiliser le VPA et le HPA en même temps ?
Oui, mais avec précaution. Le VPA et le HPA ne doivent pas cibler les mêmes métriques pour un même déploiement, sous peine de comportements imprévisibles. La bonne pratique : utilisez le VPA pour ajuster les requests/limits des workloads stables ou batch, et le HPA pour le scaling horizontal des services à trafic variable. Si vous devez absolument les combiner sur le même déploiement, configurez le VPA sur la mémoire et le HPA sur le CPU (ou utilisez des métriques personnalisées distinctes).
Karpenter fonctionne-t-il sur Azure et GCP, ou uniquement sur AWS ?
Karpenter a été initialement développé pour AWS EKS, mais en 2026, le support Azure AKS est disponible en production. Le projet est conçu de manière modulaire avec des providers spécifiques à chaque cloud. Pour GCP, le GKE Autopilot intègre des fonctionnalités similaires de provisionnement automatique. Si vous êtes sur Azure, Karpenter est une option viable. Sur GCP, tournez-vous plutôt vers le Node Auto-Provisioning (NAP) natif de GKE.
Comment éviter les interruptions de service avec les instances Spot ?
Trois mécanismes essentiels. Premièrement, utilisez les Pod Disruption Budgets (PDB) pour garantir qu'un nombre minimum de replicas reste disponible pendant les interruptions. Deuxièmement, configurez Karpenter avec plusieurs familles d'instances et zones de disponibilité — ça diversifie le risque d'interruption Spot. Troisièmement, maintenez toujours vos services critiques sur un mix Spot + on-demand. Ne mettez jamais 100 % de votre production sur du Spot (ça semble évident, mais j'ai vu des équipes le faire). Une règle courante : 70 % Spot pour les workloads tolérants, 100 % on-demand pour les bases de données et services stateful.
À quelle fréquence faut-il revoir le dimensionnement des pods et des nœuds ?
La meilleure approche combine automatisation continue et revue humaine périodique. Les outils automatisés (VPA, Karpenter) doivent fonctionner en continu pour détecter et corriger le gaspillage évident. Les équipes plateforme devraient consulter les dashboards de coûts chaque semaine lors des réunions opérationnelles. Enfin, une revue approfondie trimestrielle permet d'analyser les tendances, d'ajuster les engagements Reserved Instances ou Savings Plans, et d'affiner les stratégies en fonction de l'évolution des workloads.