Cellule FinOps : du showback au chargeback Kubernetes par namespace
FinOps & Coûts

Cellule FinOps : du showback au chargeback Kubernetes par namespace

20 septembre 20268 min de lectureFinOpsKubernetesOpenCost

Comment structurer une cellule FinOps avec un vrai mandat : KPI actionnables, progression showback vers chargeback, et allocation des coûts Kubernetes par namespace avec OpenCost.

La plupart des organisations découvrent le FinOps de la même façon : une alerte budgétaire se déclenche, quelqu'un exporte un CSV depuis la console de facturation, et un tableur circule pendant quinze jours. Puis plus rien ne change. La courbe de coûts continue de monter, parce que le problème n'a jamais été le manque de données — mais l'absence d'un propriétaire, d'une cadence de décision et d'un modèle d'allocation auquel les équipes font confiance.

Cet article décrit le modèle opérationnel qui tient dans la durée : une cellule FinOps avec un vrai mandat, une liste courte de KPI qui déclenchent des décisions, la progression showback → chargeback, et la partie technique la plus difficile — allouer les coûts Kubernetes jusqu'au namespace.

La cellule FinOps est un modèle opérationnel, pas une brigade anti-dépenses

Une cellule FinOps (ou guilde, ou chantier coûts du CCoE) existe pour faire du coût une variable d'ingénierie de premier rang, au même titre que la latence et la disponibilité. Son rôle n'est pas de dire non aux dépenses. C'est de rendre visible le coût de chaque choix d'architecture, au moment où le choix est fait, aux personnes qui le font.

Le mode d'échec classique, c'est la centralisation. Une équipe qui produit des rapports et les envoie aux équipes de dev devient une police des coûts, ignorée en un trimestre. La cellule qui fonctionne est petite, transverse, et opère comme une plateforme : elle construit la chaîne d'allocation, les dashboards, les garde-fous, puis pousse la responsabilité vers les équipes qui possèdent les workloads.

RôleContributionCharge typique
Lead FinOps / platform engineerChaîne d'allocation, outillage, qualité de la donnéeTemps plein ou majoritaire
Contrôleur de gestionBudgets, amortissements, mapping plan comptable, validation du forecastQuelques jours par mois
Architecte cloud / plateformeStratégie d'engagements, arbitrages d'architecture, standards de sizingQuelques jours par mois
Product / engineering managersPortent le coût de leur périmètre, traitent les recommandations1 à 2 heures par mois chacun
Achats / sponsorContrats, négociation EDP / engagements, escaladeTrimestriel

Trois décisions définissent le mandat : qui engage la capacité réservée et les savings plans (jamais les équipes individuellement — toujours centralisé), qui arbitre entre coût et performance (l'architecte, avec l'ingénierie), et qui est responsable d'un dépassement budgétaire (l'équipe propriétaire du périmètre, pas la cellule FinOps).

Des KPI qui pilotent, pas des KPI qui décorent

La dépense mensuelle totale est un très mauvais KPI. Elle augmente quand l'activité croît, ce qui est précisément le résultat souhaité. Ce qu'il faut, c'est un petit ensemble d'indicateurs qui séparent la croissance saine du gaspillage, et sur lesquels quelqu'un peut agir dans un sprint.

KPIDéfinitionCe qu'il révèle
Coût unitaireDépense cloud / unité métier (par commande, par utilisateur actif, par Go ingéré)Si la plateforme gagne en efficience à mesure qu'elle grandit
Taux d'allocation% de la dépense rattachée à un propriétaire identifiéLa qualité de la donnée. En dessous de 90 %, rien d'autre n'est crédible
Couverture et utilisation des engagements% d'usage éligible couvert par RI/SP/CUD, et % d'engagements consommésSi vous laissez des remises sur la table ou si vous êtes sur-engagé
Ratio d'idle / gaspillageCapacité provisionnée non utilisée (requests vs usage réel, volumes détachés, snapshots orphelins, load balancers inactifs)Le gisement d'économies immédiat, sans refonte d'architecture
Précision du forecastÉcart absolu entre prévision et réalisé, mois après moisVotre crédibilité auprès de la finance
Délai de remédiationTemps médian entre l'émission d'une recommandation et son application ou son refus expliciteSi la boucle est réellement fermée

Deux règles font survivre ces KPI. D'abord, chaque indicateur a un propriétaire nommé et un seuil qui déclenche une action, pas seulement un changement de couleur sur un dashboard. Ensuite, « refusé explicitement » est une issue valide : une recommandation rejetée pour une raison documentée (conformité, budget de latence, migration imminente) est une boucle fermée. Ce qui tue le FinOps, c'est le backlog de recommandations que personne ne regarde jamais.

Showback d'abord, chargeback ensuite — toujours

Le showback montre à chaque équipe ce qu'elle consomme et ce que cela coûte, sans impact comptable. Le chargeback refacture réellement ce coût sur le budget de l'équipe ou de la BU. Ce ne sont pas deux options alternatives : ce sont deux étapes séquentielles, et sauter la première garantit l'échec de la seconde.

ShowbackChargeback
Impact comptableAucunTransfert budgétaire réel
Qualité de donnée requiseSuffisante (~90 % alloué)Quasi parfaite et auditable
Effet comportementalPrise de conscience, optimisations opportunistesArbitrages structurels, vrais compromis
Risque principalDes rapports que personne ne litContestations sans fin sur les coûts partagés, optimisation du modèle plutôt que du coût
PrérequisUne taxonomie de tags et une chaîne d'allocationTrois à six mois de showback stable, contesté puis corrigé

Le test pratique de maturité : faites tourner le showback pendant un trimestre complet et comptez les contestations. Quand les équipes cessent de challenger leurs chiffres, le modèle est assez fiable pour porter de l'argent. Passer au chargeback avant cela transforme chaque réunion budgétaire en débat sur la donnée.

Le socle : une taxonomie de tags imposée à la création

La qualité de l'allocation se joue à la création de la ressource, pas dans la couche de reporting. Un tag ajouté a posteriori ne remonte pas dans les données de facturation historiques. La règle est simple : pas de tag obligatoire, pas de ressource.

Gardez l'ensemble obligatoire court — cinq clés maximum. Au-delà, elles seront remplies n'importe comment.

// Terraform : tags obligatoires appliqués par défaut au niveau provider
provider "aws" {
  region = "eu-west-3"
  default_tags {
    tags = {
      cost-center = var.cost_center   // clé de mapping finance
      owner       = var.team          // équipe responsable
      application = var.app_name      // produit / service
      environment = var.environment   // prod | staging | dev
      managed-by  = "terraform"
    }
  }
}

Faites appliquer la règle par un moteur de policy plutôt que par une revue de code : Service Control Policies ou Tag Policies côté AWS, Azure Policy en effet deny, org policies sur GCP, plus Conftest/OPA dans la CI pour que l'échec survienne sur la pull request et non en production.

Kubernetes : là où l'allocation devient vraiment difficile

Un cluster Kubernetes est une seule ligne de facture — un parc d'instances, un control plane managé, des volumes et des load balancers — partagée par des dizaines de workloads appartenant à des équipes différentes. La console de coûts du fournisseur ne voit pas à l'intérieur. Il faut une couche d'allocation.

L'approche de référence, implémentée par OpenCost (le projet CNCF sur lequel repose Kubecost), fonctionne ainsi : dériver un prix horaire unitaire du CPU, de la mémoire et du GPU à partir du tarif réel du nœud (on-demand, spot ou réservé), puis attribuer ce prix à chaque pod au prorata de ce qu'il consomme. Le détail critique, c'est la métrique retenue.

La formule standard facture chaque pod sur le maximum entre sa request et son usage réel, sur la fenêtre de temps :

cout_cpu_pod = Σ sur le temps (
    max(cpu_request, cpu_usage) × tarif_horaire_cpu_noeud × heures
)
cout_ram_pod = Σ sur le temps (
    max(ram_request_bytes, ram_usage_bytes) × tarif_horaire_ram_noeud × heures
)
cout_namespace = Σ cout_pod + coût PV + coût LB + coût réseau

Facturer sur les requests plutôt que sur l'usage est un choix délibéré et important. Les requests sont ce que le scheduler réserve : cette capacité est indisponible pour les autres, qu'elle soit utilisée ou non. Facturer uniquement l'usage permettrait à une équipe de demander 32 cœurs, d'en utiliser deux et de n'en payer que deux, la plateforme absorbant la différence. Le max(request, usage) rend le sur-provisionnement visible et incite directement au right-sizing — exactement le comportement recherché.

Interroger l'allocation est simple une fois OpenCost déployé :

kubectl port-forward -n opencost svc/opencost 9003:9003

curl -sG "http://localhost:9003/allocation/compute" \
  --data-urlencode "window=30d" \
  --data-urlencode "aggregate=namespace" \
  --data-urlencode "accumulate=true" \
  --data-urlencode "idle=true" \
  --data-urlencode "shareIdle=false" | jq '.data'

On peut agréger sur n'importe quel label, ce qui permet de raccrocher les namespaces à la taxonomie finance : aggregate=label:cost-center fonctionne dès lors que les namespaces portent le label. Rendez-le obligatoire avec Kyverno pour qu'un namespace ne puisse pas exister sans :

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-cost-labels
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-namespace-labels
      match:
        any:
          - resources:
              kinds: ["Namespace"]
      validate:
        message: "Les labels cost-center et owner sont obligatoires sur les namespaces."
        pattern:
          metadata:
            labels:
              cost-center: "?*"
              owner: "?*"

Les coûts partagés : la partie qui génère toutes les disputes

Entre la somme des coûts de vos namespaces et la facture réelle du cluster, il y a toujours un écart : la capacité de nœud non allouée (idle), le control plane managé, l'ingress controller, les agents d'observabilité en DaemonSet, le trafic inter-AZ, le service mesh. Cela représente facilement d'un cinquième à un tiers du coût d'un cluster, et la façon de le répartir détermine la confiance des équipes dans le modèle.

MéthodePrincipeQuand l'utiliser
Absorption plateformeLes coûts partagés restent sur le budget de l'équipe plateformeDébut de showback ; garde la conversation simple
Au prorata du coût directChaque namespace est majoré du même pourcentageLe défaut pragmatique pour le chargeback
Répartition égaleDivisé à parts égales entre namespaces ou équipesRarement équitable — pénalise les petits workloads
Node pools dédiésTaints/tolerations isolent les nœuds d'une équipe ; l'idle lui est facturéGros tenants prévisibles qui veulent le contrôle total

Quel que soit le choix, publiez la règle. Un modèle d'allocation que les équipes ne peuvent pas recalculer elles-mêmes sera contesté indéfiniment. Et gardez l'idle comme une ligne visible plutôt que de le diluer silencieusement : c'est le KPI d'efficience de l'équipe plateforme elle-même, et le masquer supprime l'incitation à améliorer le bin-packing, l'autoscaling et le dimensionnement des nœuds.

La cadence qui maintient le dispositif en vie

L'outillage représente peut-être un tiers du travail. Le reste est une question de rythme. Une revue d'anomalies hebdomadaire de 30 minutes (écart au-delà d'un seuil défini, avec un responsable nommé pour chaque ligne). Un showback mensuel avec chaque équipe, centré sur le coût unitaire et le ratio d'idle plutôt que sur la dépense absolue. Une revue trimestrielle des engagements avant les décisions de tarifs, et une réconciliation du forecast avec la finance.

Un dernier conseil : commencez par un cluster et trois équipes, pas par l'ensemble du patrimoine. Fiabilisez l'allocation, laissez les chiffres être contestés puis corrigés, publiez les règles, et généralisez seulement ensuite. Un modèle FinOps auquel la moitié de l'organisation ne croit pas est pire que pas de modèle du tout — parce qu'il consomme la crédibilité dont vous aurez besoin quand arriveront les vrais arbitrages d'architecture.

← Retour au blog