10 ans d’AWS. J’écris ce que j’aurais aimé savoir avant un incident de prod et une facture qui pique. CDK et FinOps en direct de Lille & virtually everywhere.

Lille, France
L'infra cloud, c'est 20% d'architecture et 80% de discipline. Les factures qui explosent, les incidents à 3h du matin, les migrations qui dérapent : presque jamais un problème de design. Toujours un problème de rigueur. Ici, je partage ce que j'aurais aimé lire avant.
1
4
159
Un mail de demande d'évolution. Vingt lignes, beaucoup d'intentions, quelques non-dits. D'habitude, ce genre de mail engendre une réunion, puis une seconde pour comprendre la première. Cette fois, je l'ai confié à Claude Opus 5.5 (@claudeai). Il en est sorti une story et douze sous-tickets, découpés au bon grain, chacun livrable seul. Après relecture et deux périmètres recadrés, j'ai attaqué. Les trois premiers tickets étaient livrés avant la fin de l'après-midi (ok, je viens de finir). La frontière entre ce que je délègue et ce que je garde vient de bouger d'un cran. Il reste neuf tickets, ce sera pour lundi. Là, tout de suite, direction un estaminet du Vieux-Lille, pour la seule tâche de la semaine que je ne compte pas déléguer 🍺
11
Les ressources sont taguées depuis le premier jour. Cost Explorer affiche pourtant 100 % de dépenses non allouées. Taguer et activer sont deux gestes distincts. Le tag posé sur la ressource sert à opérer. Pour qu'il apparaisse dans la facture, il faut l'activer comme tag de répartition des coûts, depuis le compte de gestion, dans la console Billing. Sans ce second geste, la donnée existe partout sauf là où elle sert à rendre des comptes. Deuxième subtilité : l'activation ne vaut que pour la suite. Une clé activée le 15 laisse la première quinzaine dans la colonne « untagged ». AWS a prévu une porte de sortie, discrète, dans la même console : le backfill, jusqu'à douze mois en arrière. Il rejoue l'activation sur l'historique, jamais le tag lui-même. Il répare donc l'oubli d'activation et reste impuissant devant l'oubli de taguer. Les ressources qui n'ont jamais porté la clé resteront anonymes pour toujours. Une facture ne se relit pas. Elle se prépare.
23
Une NAT Gateway coûte 0,048 $ de l'heure à Dublin, soit 35 $ par mois. Le tarif est affiché, la surprise est ailleurs. D'abord la haute disponibilité : une passerelle par zone, trois zones, 105 $ par mois avant le premier octet. Ensuite le traitement, 0,048 $ par Go, qui s'ajoute au transfert sortant. Un octet qui part vers internet depuis un subnet privé est donc facturé deux fois. Le plus coûteux reste ce qui n'aurait jamais dû passer par là. Une Lambda dans un VPC qui lit un objet S3, une tâche ECS qui tire son image depuis ECR, un agent qui pousse ses métriques : ce trafic ne quitte jamais AWS et se retrouve pourtant compté au tarif NAT. 500 Go téléchargés depuis S3, c'est 24 $ de traitement pour des paquets qui n'ont jamais vu internet. Le fix coûte zéro. Les endpoints de type Gateway, pour S3 et DynamoDB, sont gratuits : ni frais horaires, ni frais au Go. Deux ressources à ajouter dans la stack, et la ligne disparaît. Une architecture privée qui sort par internet pour parler à son propre fournisseur, c'est un détour facturé au kilomètre.
41
Trois lignes de log par requête, à 200 requêtes par seconde : bravo, la facture d'observabilité dépasse celle du compute. À Dublin, l'ingestion CloudWatch Logs coûte 0,57$ le Go. Le stockage revient à 0,032$ le Go par mois. Ingérer coûte donc près de vingt fois plus cher que conserver : le poste à surveiller est l'entrée, pas l'archive. 200 Go de logs par mois, c'est 114 $ d'ingestion. Doubler la verbosité double la ligne, et un niveau DEBUG resté actif après une soirée de debug fait bien plus que doubler. Deux réflexes, dans cet ordre : - vérifier d'abord la rétention : un LogGroup créé automatiquement conserve par défaut « Never expire », y compris ceux de l'environnement supprimé l'an dernier ; - sortir ensuite le niveau de log de la configuration statique, pour qu'un incident puisse passer en DEBUG le temps qu'il faut et revenir ensuite à INFO, voire WARN. Une ligne de log jamais écrite ne coûte rien. C'est bien le seul cas.
36
Un "Savings Plan" posé sur une flotte surdimensionnée, c'est un abonnement de trois ans au gaspillage, avec 30% de remise. L'ordre compte. Redimensionner d'abord, supprimer l'inutile ensuite, s'engager en dernier. Un engagement pris sur une consommation jamais nettoyée fige exactement ce qu'il aurait fallu réduire. Le piège est d'autant plus sournois que la remise flatte le tableau de bord. La facture baisse, la couverture monte, et la question de savoir si ces instances méritaient d'exister ne se pose plus. Deux mois plus tard, l'équipe redimensionne enfin. La consommation passe sous le montant engagé, et le "Savings Plan" facture le delta. Payer pour du compute qui ne tourne plus reste parfaitement possible. Mon conseil : s'engager sur le socle absolument stable, jamais sur la totalité. Une couverture à 70 % laisse la place au progrès. Une couverture à 100 % l'interdit.
30
Une pull request affiche les tests, la couverture, le lint et l'analyse de sécurité. Le montant, jamais. C'est pourtant la seule ligne que la direction lira. Une revue d'architecture décide en quinze minutes d'un poste de dépense qui vivra trois ans, et la discussion se tient sans chiffre, à l'estime, entre gens qui ont tous un avis sur les load balancers. Infracost lit le plan Terraform, le template CloudFormation ou la synthèse CDK et poste l'estimation en commentaire : +187 $/mois, dont 105 $ de RDS Proxy. Le chiffre est approximatif, il ignore le trafic réel, il se trompe sur les postes variables. Sa fonction tient ailleurs : exister avant le merge, au moment où changer d'avis coûte encore une ligne de diff. L'intégration dans la pipeline est gratuite jusqu'à mille exécutions par mois. La limite se consomme plus vite qu'il n'y paraît, chaque push relançant l'analyse : dix pull requests par jour, trois pushes chacune, et nous y voilà. Mon conseil : ne pas en faire une porte bloquante au début. Un commentaire automatique suffit à déplacer la conversation. La visibilité produit de la discipline ; l'interdiction produit surtout des contournements.
21
Un bucket S3 facture 400 Go. La console en affiche 260. La différence dort dans les uploads multipart interrompus. Un gros fichier envoyé en plusieurs parties laisse ces morceaux stockés côté S3 tant que l'upload n'est pas finalisé. Un client qui perd le réseau, une Lambda qui atteint son timeout, un pipeline tué en plein transfert : les parts déjà reçues restent. Elles sont facturées au tarif standard, elles n'apparaissent dans aucune liste d'objets, et rien ne les fait jamais expirer. La fuite est proportionnelle au volume traité. Plus le pipeline avale de fichiers, plus il en abandonne. Le fix tient en une règle de cycle de vie, à poser sur chaque bucket qui reçoit de gros objets. Sept jours d'existence pour un upload inachevé, et S3 se charge du ménage. S3 Storage Lens montre l'écart entre le stockage facturé et les objets visibles. Un bucket qui a dix ans affiche rarement zéro ;)
20
Un job d'agrégation nocturne tourne deux heures par nuit. La machine qui l'exécute facture 730 heures par mois. Le calcul est cruel de simplicité : 60 heures utiles sur 730 payées, 8 % d'utilisation. Une m5.xlarge à Dublin coûte 0,214 $ de l'heure, donc ~156 $ par mois, dont ~143 $ pour attendre minuit. L'instance reste allumée pour une raison rarement avouée : personne ne sait exactement ce qui redémarre proprement. Le cron vit sur la machine, la configuration aussi, et le disque contient trois fichiers dont l'origine s'est perdue. Éteindre demande de savoir. Laisser tourner ne demande rien. Mon conseil : commencer par le plus bête, un scheduler qui coupe à 4h et rallume à 1h. Aucune réécriture, la ligne tombe à ~19 $, et surtout le redémarrage devient un test grandeur nature, toutes les nuits. La version élégante, un EventBridge qui déclenche une tâche Fargate, viendra quand elle viendra.
33
Février 2024, AWS a commencé à facturer chaque adresse IPv4 publique. 0,005 $ de l'heure, soit 3,65 $ par mois. Attachée ou non, en production ou oubliée depuis deux ans : même tarif. Le changement est passé presque inaperçu parce qu'il ne casse rien. Aucune alerte, aucun ticket, juste une ligne de plus sur la facture. Un compte modeste porte pourtant vite son petit troupeau : vingt instances EC2 en subnet public, trois load balancers, trois NAT Gateways, une base accessible depuis l'extérieur. Vingt-sept adresses, 98 $ par mois, près de 1 200 $ par an pour le droit d'être joignable en IPv4. La console VPC propose Public IP Insights, gratuit, qui inventorie chaque adresse et la ressource qui la porte. L'audit prend une heure. Il révèle en général deux familles : les instances qui n'ont aucune raison de vivre en subnet public, et les Elastic IP réservées pour une migration terminée il y a trois ans. La rareté de l'IPv4 ne se négocie pas. L'inventaire, si.
99
Le volume gp2 est le dernier endroit où personne ne regarde. C'est pourtant la migration la moins risquée du catalogue. gp2 fait dépendre la performance de la taille : 3 IOPS par Go. Un volume de 200 Go délivre donc 600 IOPS en régime permanent et emprunte le reste à un crédit de burst, qui s'épuise exactement le jour où le trafic monte. gp3 sert 3 000 IOPS et 125 Mo/s à toute taille, sans crédit, avec 20 % de moins sur le Go. Le même volume de 200 Go à Dublin : ~22 $ par mois en gp2 pour 600 IOPS de base, ~17,60 $ en gp3 pour 3 000. Moins cher et cinq fois plus rapide au repos. La bascule se fait à chaud, sur un volume monté, sans snapshot ni redémarrage : un ModifyVolume, quelques minutes d'optimisation en tâche de fond, terminé. Au-dessus de 1 000 Go, la règle s'inverse. Un volume gp2 de 4 To embarque plus de 12 000 IOPS dans son prix. Le même en gp3 retombe à 3 000 par défaut, et personne ne s'en apercevra avant le prochain pic. Restaurer ce niveau coûte une quarantaine de dollars par mois, ce qui laisse encore gp3 gagnant, à condition d'y avoir pensé. Mon conseil : passer en masse tout ce qui fait moins de 1 To, et traiter les gros volumes un par un, métriques en main. Une baisse de facture qui divise les IOPS par quatre est un incident à crédit.
2
39
Une alerte de budget n'a jamais arrêté une facture qui s'emballe. Elle peut déclencher ce qui l'arrêtera. AWS Budgets sait faire mieux qu'envoyer un mail. Seuil franchi, trois actions sont disponibles : appliquer une politique IAM restrictive à un rôle, attacher une SCP à un compte, ou éteindre des instances EC2 et RDS nommément désignées. Chacune s'exécute automatiquement ou après approbation humaine, et AWS recommande l'approbation par défaut, avec raison. Le bon réglage tient dans un détail. Le seuil peut porter sur le prévisionnel, donc l'action se prépare avant que le montant ne soit atteint, ce qui compense la donnée de facturation qui traîne toujours de quelques heures. Un piège à connaître : les actions IAM et SCP se lèvent seules au début de la période suivante. Les instances arrêtées, elles, restent arrêtées jusqu'à ce que quelqu'un s'en occupe. Reste la moitié que la console ne fournit pas. Une alerte routée vers une adresse générique meurt dans une boîte partagée un vendredi soir. Elle doit arriver là où arrivent les incidents de production : le canal d'astreinte, avec un nom d'humain en face. Mon conseil : démarrer en approbation manuelle, avec une SCP qui interdit la création de nouvelles ressources sans toucher à l'existant. Le blocage sert à empêcher l'aggravation. L'automatique viendra quand la procédure aura été jouée une fois pour de bon.
1
29
Les crédits de bienvenue épuisés, l'histoire ne s'arrête pas. Tous les providers ont prévu un deuxième étage à la fusée : les programmes startups. Chez AWS, ça s'appelle Activate : 1000 $ en self-service pour les bootstrappés, jusqu'à 100000 $ via un fonds ou un accélérateur partenaire. Le piège serait d'y voir un chèque en blanc. Ces crédits ont deux propriétés écrites en petit : ils expirent (un à deux ans selon le palier), et ils ne se rechargent pas ! Un seul passage par palier et par entreprise. Un joker, pas un abonnement. Activer 100000 $ six mois avant le lancement produit, c'est en regarder une partie s'évaporer sur une infra qui n'a encore aucun utilisateur. Les activer trop tard, c'est avoir financé soi-même la montée en charge qu'ils étaient censés couvrir. Le bon moment n'est ni "dès que possible" ni "quand la facture pique" : c'est juste avant que le trafic ne devienne réel. D'où une chorégraphie fine entre FinOps et go-to-market. La date d'activation est une décision business, pas un formulaire à remplir un soir de motivation. Elle se cale sur la roadmap, pas sur la trésorerie. Gaspiller de l'argent gratuit reste du gaspillage : c'est un budget d'avance, pas une absence de budget.
"Le cloud, c'est quasi gratuit pour commencer." Le mythe a la vie dure. La réalité est moins romantique : rien n'est gratuit, tout est mesuré. Chaque seconde de compute, chaque Go stocké, chaque appel API incrémente un compteur quelque part. Le cloud n'est pas bon marché, il est granulaire. Nuance. Depuis mi-2025, AWS assume d'ailleurs pleinement : fini le free tier de 12 mois, place à 100 $ de crédits à l'inscription, jusqu'à 200 $ en complétant quelques activités. Ce n'est plus une période d'essai, c'est un budget. Avec un solde qui descend. Et c'est une excellente nouvelle. Parce que la vraie valeur de ces crédits n'est pas d'héberger un POC sans sortir la carte bleue : c'est d'apprendre à lire une facture pendant que les erreurs ne coûtent rien. Le solde fond plus vite que prévu ? Direction Cost Explorer, pour découvrir que la NAT Gateway du bac à sable tourne depuis trois semaines. Voilà la leçon, facturée 0 $. Mon conseil : traiter la période de crédits comme un simulateur de vol. Casser des choses, lire chaque ligne, comprendre ce qui consomme et pourquoi. Le jour où la carte bleue prend le relais, il n'y a plus de surprise. 20% d'architecture, 80% de discipline.
104
Une confession : la phobie du vendor lock-in m'a coûté cher. L'idée semblait saine. Tout le produit en docker compose : le code, le cache, et jusqu'à la base de données. Zéro service managé, zéro dépendance au provider. Promis, si le fournisseur déçoit, tout repart ailleurs en une commande. Sauf que cette liberté a un prix caché : moi. Les sauvegardes de Postgres ? Un cron maison, à surveiller. Les montées de version ? Manuel de migration ouvert un dimanche. Le disque qui se remplit, la réplication qui décroche, la restauration jamais testée qui, forcément, échoue le jour où elle sert : tout atterrit sur la même paire d'épaules. RDS fait tout ça sur étagère pour quelques dizaines d'euros par mois. J'ai troqué quelques euros contre mes nuits, et le taux de change est mauvais. Le lock-in n'est pas un danger, c'est un prix. Parfois il mérite d'être négocié, parfois d'être payé. Mon conseil : réserver l'énergie d'indépendance aux composants réellement stratégiques, et accepter le lock-in partout où le service managé fait mieux, moins cher, pendant que je dors. La portabilité parfaite d'un produit qui n'avance plus, ça ne se migre nulle part.
1
36
"Le cloud, c'est quasi gratuit pour commencer." Le mythe a la vie dure. La réalité est moins romantique : rien n'est gratuit, tout est mesuré. Chaque seconde de compute, chaque Go stocké, chaque appel API incrémente un compteur quelque part. Le cloud n'est pas bon marché, il est granulaire. Nuance. Depuis mi-2025, AWS assume d'ailleurs pleinement : fini le free tier de 12 mois, place à 100 $ de crédits à l'inscription, jusqu'à 200 $ en complétant quelques activités. Ce n'est plus une période d'essai, c'est un budget. Avec un solde qui descend. Et c'est une excellente nouvelle. Parce que la vraie valeur de ces crédits n'est pas d'héberger un POC sans sortir la carte bleue : c'est d'apprendre à lire une facture pendant que les erreurs ne coûtent rien. Le solde fond plus vite que prévu ? Direction Cost Explorer, pour découvrir que la NAT Gateway du bac à sable tourne depuis trois semaines. Voilà la leçon, facturée 0 $. Mon conseil : traiter la période de crédits comme un simulateur de vol. Casser des choses, lire chaque ligne, comprendre ce qui consomme et pourquoi. Le jour où la carte bleue prend le relais, il n'y a plus de surprise. 20% d'architecture, 80% de discipline.
1
157
Répliquer l'infrastructure de production en développement pour ne pas passer à côté d'un loup : c'est tout à l'honneur de l'équipe. Iso-prod oblige, un RDS Proxy trône devant la base. Et cette base Aurora Serverless v2 est configurée à 0 ACU minimum : le réflexe FinOps est là aussi. Sur le papier, tout est juste. Sauf que les deux s'annulent. RDS Proxy maintient une connexion ouverte en permanence, et qui dit connexion dit activité : la base ne se met jamais en pause et campe à 0,5 ACU. ~45 $/mois pour ne rien faire. Le plus savoureux : le proxy est lui-même facturé, avec un minimum de 8 ACU, soit ~100 $/mois. L'outil d'optimisation coûte deux fois le prix de la base qu'il empêche de dormir. Total : ~150 $/mois pour un environnement pensé « quasi gratuit ». La précision architecturale vient d'entrer en collision avec l'objectif FinOps, et c'est la fuite qui a gagné. Mon conseil : réserver RDS Proxy aux environnements qui vivent 24/7. En développement, une base qui dort n'a pas besoin qu'on lui tienne la main.
Un environnement de développement travaille 40 heures par semaine. Sa base de données, elle, est facturée 168 heures. Aurora Serverless v2 règle ça élégamment grâce à sa capacité minimale de 0 ACU. Sans connexion pendant la durée configurée, l'instance se met en pause. Le compute s'arrête, il ne reste que le stockage (pas vraiment le poste qui fait mal). Nuits, week-ends, jours fériés : la base dort, le compteur aussi. Maintenant, parlons du caveat. La première connexion réveille le cluster, et le réveil prend une quinzaine de secondes. Mais attention : au-delà de 24 heures de pause, l'instance passe en sommeil profond et le réveil peut prendre 30 secondes ou plus ; j'ai déjà été témoin d'un redémarrage en plusieurs minutes. Pendant ce temps, toute connexion attend... ou expire, selon le timeout du client. D'où le grand classique du lundi matin : le premier test échoue, on soupçonne le VPN, le DNS, le security group. Un développeur qui crie au loup et une heure de debug pour un faux positif ! Il suffisait de savoir patienter 30 secondes et d'ignorer ce premier "incident". Le fix ne coûte rien et tient en une bonne pratique : informer l'équipe de l'existence de ce mode sommeil de la base de données. 20% d'architecture, 80% de discipline.
60
Un environnement de développement travaille 40 heures par semaine. Sa base de données, elle, est facturée 168 heures. Aurora Serverless v2 règle ça élégamment grâce à sa capacité minimale de 0 ACU. Sans connexion pendant la durée configurée, l'instance se met en pause. Le compute s'arrête, il ne reste que le stockage (pas vraiment le poste qui fait mal). Nuits, week-ends, jours fériés : la base dort, le compteur aussi. Maintenant, parlons du caveat. La première connexion réveille le cluster, et le réveil prend une quinzaine de secondes. Mais attention : au-delà de 24 heures de pause, l'instance passe en sommeil profond et le réveil peut prendre 30 secondes ou plus ; j'ai déjà été témoin d'un redémarrage en plusieurs minutes. Pendant ce temps, toute connexion attend... ou expire, selon le timeout du client. D'où le grand classique du lundi matin : le premier test échoue, on soupçonne le VPN, le DNS, le security group. Un développeur qui crie au loup et une heure de debug pour un faux positif ! Il suffisait de savoir patienter 30 secondes et d'ignorer ce premier "incident". Le fix ne coûte rien et tient en une bonne pratique : informer l'équipe de l'existence de ce mode sommeil de la base de données. 20% d'architecture, 80% de discipline.
1
637
Un compte AWS qui a de la bouteille raconte toujours la même histoire. Ici : une infra EC2 bien tenue. Chaque semaine, Packer reconstruit une AMI fraîche, l'autoscaler fait le swap, les systèmes restent à jour. De la belle ouvrage. Sauf que personne n'a écrit la fin de l'histoire. Trois ans plus tard, plus de 150 AMIs de 8 Go dorment dans le compte : 1,2 To de snapshots EBS qui ne serviront plus jamais. À 0,05 $/Go/mois, ça fait 60 $ chaque mois, soit plus de 700 $ par an (et presque 800 $ à Paris !), pour du stockage dont la seule fonction est d'exister. Il faut faire le ménage. Attention au piège classique : désinscrire une AMI ne supprime pas ses snapshots. Depuis peu, l'AWS CLI sait le faire d'un coup (`deregister-image --delete-associated-snapshots`), mais la meilleure pratique reste Data Lifecycle Manager, pour ne conserver que les n dernières versions et laisser le reste disparaître. Une pipeline qui crée sans jamais détruire, ce n'est pas une pipeline. C'est une fuite. 20% d'architecture, 80% de discipline.
1
81
Repousser une montée de version RDS, c'est gratuit. Repousser une fin de vie, non. Quand le moteur passe obsolète, on trouve toujours toutes les bonnes raisons du monde de temporiser : la migration risquée, le sprint déjà plein, "on verra au prochain trimestre". Sauf qu'à partir de la date de fin de support, AWS branche le compteur du support étendu. En Europe : 0,112 $ / vCPU / heure les deux premières années. Une base de 4 vCPU → ~320 $/mois. Juste pour garder en vie un truc qu'il aurait fallu migrer. Les mois passent. Au bout d'un an, on a payé l'équivalent d'un MacBook Pro d'ingé. Sauf que personne ne l'a eu, ce MacBook. Il est parti en procrastination.
1
1
48
À partir de la 3ᵉ année de support étendu, le tarif double. On passe à ~0,224 $ / vCPU / heure. La même base de 4 vCPU grimpe à ~640 $/mois. Sur douze mois, ce n'est plus un MacBook parti en fumée mais 2 ! Le compteur ne récompense jamais l'attente. Il facture juste l'inaction, de plus en plus cher, jusqu'à ce que la migration qu'on repoussait devienne le poste d'économie le plus rentable de l'année.
35
Secrets Manager, c'est 0,40$/mois par secret. Ce n'est pas cher pour de la sécurité et tout le monde retient ce chiffre. Celui que personne ne budgète : 0,05$ les 10 000 appels API. Une Lambda qui lit son secret à chaque invocation, disons 1M de fois par jour, ça fait 5$ chaque jour, soit 2 cafés au comptoir. 130$/mois pour relire 10 secrets chaque seconde... 10 secrets dont la valeur n'a pas changé depuis Noël ! Le fix tient en une ligne de discipline : charger le secret HORS du handler. Tout ce qui s'exécute à l'init du module survit tant qu'AWS garde le conteneur chaud. Le secret est lu une fois par cold start, puis servi gratuitement depuis la mémoire à chaque invocation suivante. Un cache offert par le cycle de vie Lambda - encore faut-il savoir qu'il existe. Bonus : l'extension AWS Parameters and Secrets gère ça proprement (TTL, refresh) si le secret doit pouvoir tourner sans redéploiement des Lambdas. 20% d'architecture, 80% de discipline.
49