Aller au contenu principal
FinOpsCloudOptimisation

FinOps : Kubecost, Infracost et right-sizing

30 min de lecture Platform Engineering — Chapitre 5

Le framework FinOps, visibilité des coûts avec Kubecost, estimation pré-déploiement avec Infracost et right-sizing pour ne payer que ce que tu utilises.

Le cloud a résolu le problème du provisioning matériel. En quelques clics, tu lances des dizaines de serveurs, des bases de données managées, des clusters Kubernetes. Mais cette facilité a un prix — littéralement. Sans discipline, les factures cloud explosent et personne ne sait exactement qui consomme quoi, ni pourquoi.

Le FinOps (Financial Operations) est la discipline qui réconcilie vélocité technique et maîtrise financière. Ce n’est pas “dépenser moins” — c’est dépenser mieux, en donnant à chaque équipe la visibilité et la responsabilité de ses coûts. Dans ce cours, on installe les deux outils clés de l’écosystème : Kubecost pour la visibilité en temps réel sur Kubernetes, et Infracost pour anticiper les coûts avant même de déployer.


Le framework FinOps — Les fondations

Le FinOps, formalisé par la FinOps Foundation, repose sur un cycle itératif en trois phases : Inform (qui dépense combien ?), Optimize (comment réduire sans casser ?) et Operate (comment gouverner dans la durée ?).

Les six principes fondateurs sont clairs : les équipes Engineering, Finance et Business collaborent ensemble ; chaque équipe est responsable de ses coûts ; un groupe centralisé (Cloud Center of Excellence) pilote la stratégie ; les rapports sont accessibles en temps réel ; les décisions sont guidées par la valeur business, pas par le coût brut ; et le modèle variable du cloud est un avantage, pas un problème.

🔥 Cas réel : Une scale-up SaaS européenne de 80 ingénieurs a découvert, après audit FinOps, que 40% de sa facture AWS provenait d’environnements de développement allumés 24/7 — week-ends et nuits inclus. En implémentant un simple scheduling on/off (cron Kubernetes + Lambda), elle a économisé 180k€/an sans toucher à la production.

Les erreurs classiques qui gonflent la facture :

  • Environnements de dev allumés 24/7 alors que personne ne travaille la nuit ni le week-end
  • Instances oversized — ce m5.4xlarge qui tourne à 5% de CPU
  • Volumes EBS orphelins — l’instance est supprimée, le disque reste et facture
  • Snapshots accumulés — 3 ans de snapshots quotidiens que personne n’utilise
  • NAT Gateway — le service le plus cher que personne ne surveille

⚠️ Attention : Le NAT Gateway AWS coûte ~0.045$/GB de données traitées. Un cluster Kubernetes qui tire beaucoup d’images Docker ou qui communique avec des APIs externes peut facilement générer 500-1000$/mois de NAT Gateway seul. Vérifie cette ligne en premier dans ta facture.


Kubecost — Visibilité des coûts Kubernetes

Kubecost est l’outil de référence pour comprendre combien coûte chaque namespace, deployment, pod et même container dans ton cluster Kubernetes. Il combine les métriques Prometheus avec les prix réels de ton cloud provider pour produire une allocation de coûts précise.

L’installation se fait via Helm. Kubecost déploie son propre Prometheus (ou se branche sur un existant), un backend d’analyse de coûts (cost-model) et une interface web :

# Installation Kubecost via Helm
helm repo add kubecost https://kubecost.github.io/cost-analyzer/
helm repo update

helm install kubecost kubecost/cost-analyzer \
  --namespace kubecost \
  --create-namespace \
  --set kubecostToken="ton-token" \
  --set prometheus.server.persistentVolume.size=32Gi \
  --set persistentVolume.size=32Gi

Pour une configuration production, il faut connecter Kubecost à l’API de facturation de ton cloud provider (AWS Cost and Usage Report, GCP BigQuery, Azure Cost Management). Cela permet de réconcilier les coûts estimés avec les coûts réels facturés, et d’intégrer les remises (Reserved Instances, Savings Plans) :

# values.yaml — Configuration Kubecost avancée
kubecostProductConfigs:
  clusterName: "production-eu-west-1"
  currencyCode: "EUR"
  athenaProjectID: "123456789012"
  athenaBucketName: "s3://kubecost-cur-reports"
  athenaRegion: "eu-west-1"
  athenaDatabase: "athenacurcfn_kubecost"
  athenaTable: "kubecost_cur"

  alertConfigs:
    enabled: true
    alerts:
      - type: budget
        threshold: 500          # Alerte si namespace > 500€/jour
        window: daily
        aggregation: namespace
        filter: '*'
      - type: efficiency
        threshold: 0.8          # Alerte si efficacité < 80%
        window: weekly
        aggregation: cluster

L’API Kubecost est extrêmement puissante pour automatiser la détection d’anomalies et alimenter des dashboards custom :

# Coûts par namespace sur les 7 derniers jours
curl -s "http://kubecost:9090/model/allocation?window=7d&aggregate=namespace" \
  | jq '.data[0] | to_entries[] | 
    {namespace: .key, cost: .value.totalCost} | select(.cost > 1)'

# Recommandations de right-sizing automatiques
curl -s "http://kubecost:9090/model/savings/requestSizing?window=72h" \
  | jq '.[0:5] | .[] | {
    container: .containerName,
    namespace: .namespace,
    currentCPU: .currentRequest.cpu,
    recommendedCPU: .recommendedRequest.cpu,
    monthlySavings: .monthlySavings
  }'

💡 Tip DevOps : Pour que l’allocation de coûts fonctionne correctement, chaque Deployment doit porter des labels FinOps standardisés (cost-center, team, environment, product). Sans ça, Kubecost ne peut pas dire “l’équipe checkout dépense X€/mois” — et le FinOps perd tout son intérêt.


Infracost — Le coût avant le déploiement

Infracost prend l’approche shift-left : il estime le coût d’un changement Terraform avant qu’il soit appliqué. Intégré dans la CI/CD, il poste un commentaire sur chaque Pull Request avec l’impact financier du changement proposé.

Le principe : quand un développeur modifie un fichier Terraform pour ajouter une instance RDS db.r5.2xlarge, le reviewer voit immédiatement “+1 234$/mois” dans le commentaire de la PR. C’est un moment de décision : est-ce que cette instance vaut ce prix, ou est-ce qu’un db.r5.large suffirait ?

Voici l’intégration GitHub Actions complète :

# .github/workflows/infracost.yml
name: Infracost
on:
  pull_request:
    paths: ['terraform/**']

jobs:
  infracost:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - uses: infracost/actions/setup@v3
        with:
          api-key: ${{ secrets.INFRACOST_API_KEY }}

      - name: Checkout base branch
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.base.ref }}
          path: base

      - name: Generate baseline
        run: infracost breakdown --path=base/terraform/production
          --format=json --out-file=/tmp/infracost-base.json

      - name: Generate diff
        run: infracost diff --path=terraform/production
          --compare-to=/tmp/infracost-base.json
          --format=json --out-file=/tmp/infracost-diff.json

      - name: Post comment
        run: infracost comment github
          --path=/tmp/infracost-diff.json
          --repo=${{ github.repository }}
          --pull-request=${{ github.event.pull_request.number }}
          --github-token=${{ secrets.GITHUB_TOKEN }}
          --behavior=update

      - name: Check threshold
        run: |
          DIFF=$(jq '.diffTotalMonthlyCost | tonumber' /tmp/infracost-diff.json)
          if (( $(echo "$DIFF > 500" | bc -l) )); then
            echo "::error::Cost increase exceeds 500$/month"
            exit 1
          fi

Pour aller plus loin, Infracost supporte les policies OPA (Open Policy Agent) qui permettent de refuser automatiquement certains changements trop coûteux :

# policy.rego — Règles de coûts avec Open Policy Agent
package infracost

deny[msg] {
    r := input.projects[_].breakdown.resources[_]
    r.resourceType == "aws_instance"
    r.monthlyCost > 500
    msg := sprintf("Instance %s coûte %v$/mois (max: 500$)", [r.name, r.monthlyCost])
}

warn[msg] {
    r := input.projects[_].breakdown.resources[_]
    r.resourceType == "aws_nat_gateway"
    msg := sprintf("NAT Gateway %s coûte %v$/mois — est-ce nécessaire ?", [r.name, r.monthlyCost])
}

🧠 À retenir : Infracost ne remplace pas le monitoring des coûts réels (Kubecost, AWS Cost Explorer). C’est un filet de sécurité en amont. Les deux sont complémentaires : Infracost prévient, Kubecost constate.


Right-sizing — Ne payer que ce qu’on utilise

Le right-sizing est souvent le quick win le plus rentable en FinOps. Le problème est universel : les développeurs demandent 4 CPU et 8 GiB de RAM “au cas où”, le service en utilise réellement 0.3 CPU et 1.2 GiB. À l’échelle de 200 pods, ce gaspillage de 85% représente des milliers d’euros par mois.

La première étape est de mesurer l’écart entre les requests déclarées et l’usage réel. En Kubernetes, les requêtes PromQL suivantes identifient les pods sur-provisionnés :

# Pods dont l'usage CPU est inférieur à 20% des requests (sur 24h)
# → Candidats immédiats au right-sizing
(
  sum by (namespace, pod) (rate(container_cpu_usage_seconds_total[24h]))
  /
  sum by (namespace, pod) (kube_pod_container_resource_requests{resource="cpu"})
) < 0.2

Le Vertical Pod Autoscaler (VPA) automatise le right-sizing. En mode Off, il observe et recommande sans toucher à rien — c’est le mode idéal pour commencer. En mode Auto, il applique automatiquement les recommandations en recréant les pods :

# VPA en mode recommandation (safe pour démarrer)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: payment-service-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: payment-service
  updatePolicy:
    updateMode: "Off"    # Recommandations only, pas de restart
  resourcePolicy:
    containerPolicies:
      - containerName: payment
        minAllowed:
          cpu: "100m"
          memory: "128Mi"
        maxAllowed:
          cpu: "2"
          memory: "4Gi"

⚠️ Attention : Ne passe jamais directement en mode Auto sur un service critique en production. Commence par Off pendant 2 semaines, valide les recommandations manuellement, puis passe en Auto sur les services non-critiques d’abord. Le VPA en mode Auto redémarre les pods pour appliquer les nouvelles requests — ça peut impacter la disponibilité si ton PodDisruptionBudget n’est pas correctement configuré.

Pour les instances cloud (EC2, Compute Engine), un script d’analyse identifie rapidement les machines sous-utilisées en interrogeant CloudWatch :

#!/usr/bin/env python3
"""Recommandation de right-sizing AWS EC2"""
import boto3
from datetime import datetime, timedelta

cw = boto3.client('cloudwatch')
ec2 = boto3.client('ec2')

def get_avg_cpu(instance_id, days=14):
    resp = cw.get_metric_statistics(
        Namespace='AWS/EC2', MetricName='CPUUtilization',
        Dimensions=[{'Name': 'InstanceId', 'Value': instance_id}],
        StartTime=datetime.utcnow() - timedelta(days=days),
        EndTime=datetime.utcnow(), Period=3600,
        Statistics=['Average', 'Maximum'])
    if not resp['Datapoints']: return 0, 0
    avg = sum(d['Average'] for d in resp['Datapoints']) / len(resp['Datapoints'])
    return avg, max(d['Maximum'] for d in resp['Datapoints'])

instances = ec2.describe_instances(
    Filters=[{'Name': 'instance-state-name', 'Values': ['running']}])

for r in instances['Reservations']:
    for i in r['Instances']:
        avg, mx = get_avg_cpu(i['InstanceId'])
        action = "⬇️ DOWNSIZE" if avg < 10 else "✅ OK" if avg < 80 else "⬆️ UPSIZE"
        print(f"{i['InstanceId']:<20} {i['InstanceType']:<15} {avg:.1f}% avg  {action}")

🔥 Cas réel : Un e-commerce a appliqué les recommandations VPA sur ses 150 microservices en production. Résultat : les requests CPU totales sont passées de 480 vCPU à 185 vCPU, permettant de réduire le cluster de 60 à 25 nœuds. Économie : 12 000€/mois, soit 144k€/an — le salaire d’un ingénieur financé par du right-sizing.


Bonnes pratiques et pièges à éviter

Ce qui fonctionne :

  • Rendre les coûts visibles à chaque équipe via un dashboard partagé (pas réservé au management)
  • Intégrer Infracost dans les PR dès le premier jour — l’habitude se prend vite
  • Commencer le VPA en mode Off et valider manuellement avant d’automatiser
  • Planifier un “FinOps review” mensuel de 30 minutes par équipe
  • Automatiser l’extinction des environnements de dev hors heures ouvrées

Ce qui échoue :

  • Donner la responsabilité des coûts uniquement à l’équipe Ops (c’est l’affaire de tous)
  • Optimiser sans baseline — tu ne sauras jamais combien tu as économisé
  • Right-sizer trop agressivement et provoquer des OOMKills en production
  • Ignorer les coûts réseau (NAT Gateway, data transfer inter-AZ)
  • Acheter des Reserved Instances avant d’avoir stabilisé l’usage

💡 Tip DevOps : La règle des 80/20 s’applique au FinOps. 80% de tes économies viendront de 3 actions : éteindre les env de dev la nuit, right-sizer les 10 plus gros workloads, et acheter des Savings Plans sur les ressources stables. Ne te perds pas dans l’optimisation des centimes.


Résumé

Le FinOps structure la gestion des coûts cloud en trois phases (Inform, Optimize, Operate) portées par toute l’organisation, pas seulement les Ops. Kubecost fournit la visibilité temps réel sur les coûts Kubernetes avec allocation par namespace, équipe et label. Infracost décale le contrôle des coûts en amont en estimant l’impact financier de chaque PR Terraform. Le right-sizing, qu’il soit manuel (PromQL + analyse) ou automatisé (VPA), est systématiquement le quick win le plus rentable — 30 à 50% d’économies sur les workloads Kubernetes sont la norme, pas l’exception.

🧠 À retenir : Le FinOps n’est pas un projet ponctuel. C’est une pratique continue, un muscle que l’organisation renforce itération après itération. Les outils sont importants, mais la culture de responsabilité partagée des coûts l’est encore plus.

Prochain cours : On continue le volet financier avec les Spot Instances, les stratégies de tagging et les budgets cloud — les leviers opérationnels pour passer de la visibilité à l’action.

🖥️ Pratique sur ton propre serveur

Pour suivre Platform Engineering en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.

Obtenir 200$

Articles liés