Utiliser Terraform en équipe
Adopter l'IaC en équipe et bâtir un workflow de déploiement de l'infrastructure : gestion de version, règle d'or de Terraform, et pipeline CI/CD.
Jusqu'ici, tout au long de ce livre, vous avez probablement travaillé seul, sur votre poste, en lançant terraform apply à la main quand bon vous semblait. Dans la vraie vie, vous travaillerez au sein d'une équipe, ce qui change tout : il faut convaincre vos collègues d'adopter l'infrastructure as code (IaC), gérer plusieurs personnes qui modifient le même code en parallèle, et faire entrer Terraform dans le reste de la chaîne d'outils de l'entreprise. Ce chapitre est le dernier du livre, et il rassemble tous les fils précédents en un processus unique : comment faire fonctionner Terraform et l'IaC pour une équipe, depuis l'adoption culturelle jusqu'au pipeline de déploiement automatisé.
Adopter l'IaC dans votre organisation
Si votre équipe a l'habitude de gérer toute l'infrastructure à la main, passer à l'infrastructure as code ne consiste pas seulement à introduire un nouvel outil : il faut changer la culture et les processus de l'équipe. C'est un chantier considérable, surtout dans une grande entreprise, et comme chaque culture est un peu différente, il n'existe pas de recette unique. Trois conseils restent toutefois utiles dans la plupart des situations : convaincre votre hiérarchie, avancer de façon incrémentale, et donner à votre équipe le temps d'apprendre.
Convaincre votre hiérarchie
Le scénario se répète dans bien des entreprises : un développeur découvre Terraform, s'enthousiasme, arrive au travail plein d'énergie, montre l'outil à tout le monde… et le manager dit « non ». Le développeur, frustré, ne comprend pas : pourquoi les autres ne voient-ils pas les bénéfices ? Le problème, c'est que ce développeur voit tous les bénéfices de l'IaC, mais aucun de ses coûts. Or ces coûts sont réels :
- Le déficit de compétences (skills gap) : passer à l'IaC signifie que votre équipe d'exploitation (Ops) va passer le plus clair de son temps à écrire du code — modules Terraform, tests Go, recettes Chef. Certains ingénieurs adoreront ; d'autres, habitués aux changements manuels avec un script occasionnel, vivront difficilement cette transition vers le génie logiciel à plein temps.
- Les nouveaux outils : certains développeurs sont presque religieusement attachés à leurs outils. Chaque nouvel outil ravira les uns et fera résister les autres, peu désireux d'investir du temps dans de nouveaux langages.
- Le changement de mentalité (change in mindset) : qui gère son infrastructure à la main fait ses changements directement (se connecter en SSH, lancer quelques commandes). L'IaC impose de faire chaque changement indirectement : éditer du code, le commiter, puis laisser un processus automatisé l'appliquer. Cette couche d'indirection peut sembler plus lente pour les tâches simples, surtout pendant l'apprentissage.
- Le coût d'opportunité (opportunity cost) : investir du temps dans la migration IaC, c'est ne pas l'investir ailleurs. Quels projets faut-il mettre en attente, et sont-ils importants ?
Votre manager sera particulièrement sensible à ce coût d'opportunité. L'une de ses responsabilités est de s'assurer que l'équipe travaille sur les projets les plus prioritaires. Quand vous arrivez tout excité à parler de Terraform, ce qu'il entend peut-être, c'est : « oh non, ça a l'air d'un chantier énorme, combien de temps va-t-il prendre ? » Si vous passez ce temps sur Terraform, vous ne déployez pas la nouvelle appli que l'équipe de recherche réclame depuis des mois, vous ne préparez pas l'audit PCI, vous n'analysez pas la panne de la semaine dernière. Votre objectif n'est donc pas de prouver que l'IaC a de la valeur, mais qu'elle apportera plus de valeur à l'équipe que n'importe quel autre chantier sur la même période.
La pire manière de s'y prendre est de réciter les fonctionnalités de votre outil favori : « Terraform est déclaratif, multicloud, open source ». Les développeurs gagneraient ici à s'inspirer des commerciaux. Une technique un peu meilleure consiste à parler des bénéfices : au lieu de « le produit X fait Y », dites « vous pouvez faire Y grâce au produit X ». Montrez à votre interlocuteur les nouveaux superpouvoirs que l'outil lui donne. Plutôt que « Terraform est déclaratif », parlez de projets livrés plus vite. Plutôt que « Terraform est multicloud », parlez de la sérénité d'une éventuelle migration de cloud sans avoir à tout réoutiller. Plutôt que « Terraform est open source », montrez combien il sera plus facile de recruter dans une large communauté active.
Mais les meilleurs commerciaux savent une stratégie encore plus efficace : se concentrer sur les problèmes. Observez un excellent vendeur en clientèle, et vous verrez que c'est le client qui parle le plus ; le vendeur écoute, à la recherche d'une seule chose : quel est le problème majeur que ce client cherche à résoudre, quel est son point de douleur le plus aigu ? Parlez à votre manager pour comprendre ses problèmes les plus importants du trimestre ou de l'année. Vous découvrirez peut-être que l'IaC ne les résoudrait pas. Et c'est très bien ainsi !
Note
Il est presque hérétique pour l'auteur d'un livre sur Terraform de l'écrire, mais toutes les équipes n'ont pas besoin d'IaC. L'adoption a un coût relativement élevé : elle paiera à long terme dans certains cas, pas dans d'autres. Une petite startup avec un seul Ops, un prototype jetable dans quelques mois, un projet perso pour le plaisir : la gestion manuelle est souvent le bon choix.
En revanche, si l'un des problèmes-clés de votre manager peut être résolu par l'IaC, montrez-lui à quoi ce monde ressemblerait. Supposons que sa priorité du trimestre soit d'améliorer la disponibilité (uptime) : enchaînement de pannes, des heures d'indisponibilité, des clients qui se plaignent, le PDG sur le dos. En creusant, vous découvrez que plus de la moitié de ces pannes venaient d'une erreur manuelle lors d'un déploiement : étape oubliée, serveur mal configuré, ou infrastructure de staging qui ne correspondait pas à la production. Alors, au lieu de parler des fonctionnalités de Terraform, ouvrez par : « J'ai une idée pour réduire nos pannes de moitié. » Je vous garantis que cela captera son attention. Peignez le tableau d'un processus de déploiement entièrement automatisé, fiable, reproductible, où les erreurs manuelles ayant causé la moitié des pannes deviennent impossibles — et où des tests automatisés réduisent encore les pannes et doublent la cadence de déploiement.
Avancer de façon incrémentale
L'une des leçons les plus importantes de la carrière de Brikman : la plupart des grands projets logiciels échouent. Environ trois petits projets IT sur quatre (moins d'un million de dollars) aboutissent, mais seulement un grand projet sur dix (plus de dix millions) est livré dans les temps et le budget, et plus d'un tiers ne sont jamais terminés. D'où l'inquiétude devant une équipe qui veut adopter l'IaC d'un seul coup, sur une masse énorme d'infrastructure, à travers toutes les équipes, souvent dans le cadre d'une initiative encore plus vaste. Les ordres de marche d'un PDG — « tout doit migrer vers le cloud, fermer les datacenters, et tout le monde fera du DevOps, le tout en six mois » — débouchent invariablement sur un échec : deux ou trois ans plus tard, la migration tourne encore, le vieux datacenter fonctionne toujours, et personne ne sait s'ils font vraiment du DevOps.
La seule manière saine de réussir une migration est de procéder de façon incrémentale. La clé de l'incrémentalisme n'est pas seulement de découper le travail en petites étapes, mais de le découper de telle sorte que chaque étape apporte sa propre valeur — même si les étapes suivantes n'ont jamais lieu.
À retenir
Méfiez-vous du faux incrémentalisme : un gros projet découpé en petites étapes, mais qui n'offre aucune valeur réelle avant la toute dernière. On réécrit le frontend (mais sans le lancer, car il dépend d'un nouveau backend), puis le backend (mais sans le lancer, faute de migration de données), puis enfin on migre les données. Si le projet est annulé en cours de route — ce qui arrive souvent quand il déborde —, vous avez payé un coût énorme pour zéro valeur en retour : le pire résultat possible.
La meilleure approche est de résoudre un seul problème concret à la fois. Au lieu d'une migration « big bang » vers le cloud, identifiez une appli ou une équipe en difficulté, et migrez-la, elle seule. Au lieu d'un passage « big bang » au DevOps, ciblez un problème précis (les pannes lors des déploiements) et automatisez avec Terraform le déploiement le plus problématique. Une victoire rapide sur un vrai problème rend une équipe heureuse, qui devient votre ambassadrice, ce qui débloque le soutien pour la victoire suivante. En livrant de la valeur tôt et souvent, vous bâtissez de l'élan — et même si la grande migration capote, au moins une équipe et un processus de déploiement fonctionnent mieux.
Donner à l'équipe le temps d'apprendre
L'adoption de l'IaC est un investissement sérieux ; elle ne se fera ni du jour au lendemain, ni magiquement parce que le manager a hoché la tête. Si votre équipe n'obtient pas le temps et les ressources nécessaires, voici comment l'histoire finit :
- Un développeur passionné écrit pendant des mois un magnifique code Terraform et déploie beaucoup d'infrastructure.
- Il est productif et heureux, mais le reste de l'équipe n'a pas eu le temps d'apprendre Terraform.
- L'inévitable survient : une panne.
- Un autre coéquipier doit la régler. Il a deux options : (a) corriger à la main comme toujours, en quelques minutes, ou (b) corriger via Terraform, qu'il maîtrise mal, ce qui prendra des heures. Une personne rationnelle choisira presque toujours (a).
- Or, à cause de ce changement manuel, le code Terraform ne correspond plus à ce qui est déployé. Le prochain qui tentera (b) tombera sur une erreur étrange, perdra confiance, et reviendra à (a). Le code dérive encore davantage de la réalité. Un cercle vicieux s'enclenche.
- En un temps record, tout le monde refait tout à la main, le code Terraform est inutilisable, et les mois passés à l'écrire sont gâchés.
Ce n'est pas une fiction : c'est ce qui arrive dans bien des entreprises, avec de coûteuses bases de code Terraform qui prennent la poussière. Il faut donc non seulement convaincre votre manager, mais aussi donner à chacun le temps d'apprendre l'outil et de l'intérioriser, pour qu'à la prochaine panne, il soit plus facile de corriger en code qu'à la main. Ce qui aide énormément, c'est de disposer d'un processus bien défini pour l'utiliser. En petite équipe, lancer Terraform de façon ad hoc sur le poste d'un développeur suffit. Mais avec la croissance, il faut un workflow systématique, reproductible et automatisé.
Un workflow pour déployer le code applicatif
Avant de plonger dans le workflow de l'infrastructure, comparons-le à celui, bien mieux connu, du code applicatif (une appli Ruby on Rails ou Java/Spring). Cela servira de point de repère, car le workflow de l'infrastructure n'est pas aussi répandu dans l'industrie. Le voici, étape par étape :
Workflow du code applicatif
1. Gestion de version git clone ; travailler sur une branche
2. Exécuter en local ruby web-server.rb (localhost)
3. Modifier le code itérer : changer → rejouer les tests
4. Soumettre la revue pull request sur GitHub
5. Tests automatisés CI (Jenkins, CircleCI, TravisCI) sur chaque commit
6. Fusionner & releaser merge sur master + git tag → artefact versionné
7. Déployer promouvoir l'artefact d'un env à l'autre Deux points méritent l'attention pour la suite. D'abord, tout le code doit être en gestion de version (version control), sans exception — c'était déjà le premier point du fameux Joel Test il y a vingt ans. Ensuite, et c'est crucial : les tests applicatifs, manuels comme automatisés, tournent intégralement en local, sur votre propre ordinateur. Vous lancez ruby web-server.rb, vous testez avec curl http://localhost:8000, ou vous exécutez ruby web-server-test.rb. Nous verrons que ce n'est pas vrai pour l'infrastructure.
Au moment de la release, si vous suivez des pratiques d'infrastructure immuable, releaser signifie empaqueter le code dans un artefact immuable et versionné : une image Docker, une AMI, un .jar. Cet artefact ne change jamais et porte un numéro de version unique. Le déploiement, lui, offre tout un éventail de stratégies : rolling deployment (avec ou sans remplacement), blue-green, ou canary deployment (où une copie « canari » est comparée à une copie « témoin » avant de poursuivre, souvent combinée à des feature toggles). Le déploiement doit s'exécuter depuis un serveur de CI, jamais depuis le poste d'un développeur : cela force l'automatisation complète, garantit un environnement cohérent, et permet une meilleure gestion des permissions. Enfin, on promeut le même artefact versionné d'un environnement à l'autre : Dev, puis Staging, puis Production.
Un workflow pour déployer le code d'infrastructure
En surface, le workflow de l'infrastructure est identique : git clone, exécuter en local, modifier, soumettre à la revue, tests automatisés, fusionner et releaser, déployer. Mais sous le capot, les différences sont importantes — et chaque étape mérite d'être reliée à son équivalent applicatif.
Gestion de version : repo modules et repo live
Tout votre code d'infrastructure doit être en gestion de version, mais avec quelques exigences supplémentaires. Comme vu au chapitre 4, vous voudrez au moins deux dépôts distincts pour votre code Terraform :
- un repo modules, où vous créez vos modules réutilisables et versionnés (
cluster/asg-rolling-deploy,data-stores/mysql,networking/alb,services/hello-world-app) ; - un repo live, qui définit l'infrastructure réellement déployée dans chaque environnement (Dev, Stage, Prod…).
Un schéma qui fonctionne bien : avoir une équipe infrastructure spécialisée dans la création de modules robustes, de qualité production. Cette équipe crée un levier remarquable en bâtissant une bibliothèque de modules — chacun doté d'une API composable, soigneusement documenté (avec de la documentation exécutable dans le dossier examples), couvert par des tests automatisés, versionné, et respectant la checklist d'infrastructure de qualité production de l'entreprise (sécurité, conformité, scalabilité, haute disponibilité, supervision). Toutes les autres équipes consomment alors ces modules, un peu comme un catalogue de services, sans devoir réassembler l'infrastructure à zéro, et sans que l'équipe Ops devienne un goulot d'étranglement. Comme chaque équipe utilise les mêmes modules canoniques, l'équipe Ops peut pousser de nouvelles versions à toutes les équipes pour que tout reste cohérent et maintenable.
La règle d'or de Terraform
Voici un test rapide de la santé de votre code Terraform : allez dans le repo live, choisissez plusieurs dossiers au hasard, et lancez terraform plan dans chacun. Si la sortie est toujours « no changes », parfait : votre code correspond à ce qui est déployé. Si elle montre parfois un petit diff, accompagné d'une excuse (« ah oui, j'ai bidouillé ce truc à la main et oublié de mettre à jour le code »), votre code ne reflète plus la réalité, et l'ennui approche. Si terraform plan échoue avec des erreurs bizarres, ou affiche un diff gigantesque à chaque fois, votre code n'a plus aucun lien avec la réalité et ne sert plus à rien.
À retenir
La règle d'or de Terraform (Golden Rule of Terraform) : la branche master du repo live doit être une représentation 1:1 de ce qui est réellement déployé en production.
Décomposons cette phrase, de la fin vers le début :
- « …ce qui est réellement déployé » : la seule façon de garantir que le code du repo live reflète l'infrastructure réelle est de ne jamais faire de changement hors-bande (out-of-band). Une fois Terraform adopté, on ne modifie plus rien via une interface web, des appels d'API manuels, ou tout autre mécanisme. Les changements hors-bande créent des bugs compliqués et annulent une bonne partie des bénéfices de l'IaC.
- « …une représentation 1:1… » : en parcourant votre repo live, je dois pouvoir voir d'un coup d'œil quelles ressources sont déployées dans quels environnements. Chaque ressource doit correspondre à une ligne de code commitée. C'est étonnamment facile à rater : les changements hors-bande en sont une cause ; une cause plus subtile est l'usage des workspaces Terraform pour gérer les environnements — le code n'existe alors qu'en un seul exemplaire, même avec trois ou trente environnements déployés, et rien dans le code ne révèle ce qui tourne réellement. Préférez donc un dossier séparé par environnement, avec des fichiers séparés.
- « La branche master… » : on ne doit avoir à regarder qu'une seule branche pour savoir ce qui est en production. Tout changement affectant la production passe directement dans
master(une branche temporaire n'existe que pour ouvrir une pull request destinée à être fusionnée), et l'on ne lanceterraform applypour la production que contremaster.
Le problème des branches
Au chapitre 3, les mécanismes de verrouillage (locking) des backends Terraform empêchaient deux personnes lançant terraform apply simultanément sur la même configuration d'écraser leurs changements mutuels. Mais cela ne résout qu'une partie du problème : le locking protège l'état (state), pas le code Terraform lui-même. Si deux coéquipiers déploient le même code vers le même environnement mais depuis des branches différentes, vous aurez des conflits que le locking ne peut pas prévenir.
Imaginez l'application « foo », une simple instance EC2. Anna en augmente le instance_type de t2.micro à t2.medium et déploie en Staging :
resource "aws_instance" "foo" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.medium"
} Pendant ce temps, Bill, sur une autre branche, veut juste ajouter un tag. Mais son code part de l'ancienne valeur t2.micro, car les changements d'Anna sont sur une autre branche. Voici ce que voit Bill :
$ terraform plan
Terraform will perform the following actions:
# aws_instance.foo will be updated in-place
~ resource "aws_instance" "foo" {
ami = "ami-0c55b159cbfafe1f0"
id = "i-096430d595c80cb53"
instance_state = "running"
~ instance_type = "t2.medium" -> "t2.micro"
+ tags = {
+ "Name" = "foo"
}
}
Plan: 0 to add, 1 to change, 0 to destroy. Aïe : Bill s'apprête à annuler le changement d'Anna ! S'il lit attentivement la sortie du plan, il repérera l'erreur avant qu'elle n'affecte Anna. Le locking n'aide en rien ici, car le conflit n'a rien à voir avec une modification concurrente du fichier d'état : Bill et Anna pourraient appliquer leurs changements à des semaines d'intervalle, le problème serait le même. La cause profonde, c'est que les branches et Terraform font mauvais ménage. Terraform est implicitement une projection du code vers l'infrastructure du monde réel. Comme il n'y a qu'un seul monde réel, avoir plusieurs branches de code Terraform n'a guère de sens. Pour tout environnement partagé (Stage, Prod), déployez toujours depuis une seule branche.
Exécuter le code en local
Une fois le code récupéré, on l'exécute. Le piège, avec Terraform : contrairement au code applicatif, il n'y a pas de localhost. On ne peut pas déployer un ASG AWS sur son portable. La seule manière de tester manuellement du code Terraform est de le lancer dans un environnement bac à sable (sandbox) — idéalement un compte AWS dédié par développeur. On lance alors terraform apply, on vérifie avec curl, et l'on exécute les tests Go avec go test dans un compte AWS dédié aux tests.
$ terraform apply
Apply complete! Resources: 5 added, 0 changed, 0 destroyed.
Outputs:
alb_dns_name = hello-world-stage-477699288.us-east-2.elb.amazonaws.com
$ curl hello-world-stage-477699288.us-east-2.elb.amazonaws.com
Hello, World Modifier le code
On itère ensuite comme avec le code applicatif : chaque changement suivi d'un terraform apply puis d'un curl ou d'un go test. La différence est que les tests d'infrastructure sont bien plus lents ; il faut donc réfléchir à raccourcir la boucle de feedback. Les étapes de test (test stages, vues au chapitre 7) permettent de ne rejouer que certaines portions de la suite. Par exemple, en sautant les étapes de démontage (teardown) au premier lancement, on laisse l'appli et la base déployées :
$ SKIP_teardown_db=true
SKIP_teardown_app=true
go test -timeout 30m -run 'TestHelloWorldAppStageWithStages' Puis, à chaque changement de l'appli, on saute aussi le déploiement de la base, ne gardant que le déploiement de l'appli et sa validation — ce qui fait passer la boucle de feedback de plusieurs minutes à 13 secondes, un gain considérable de productivité.
Soumettre à la revue
Comme pour le code applicatif, on crée une pull request. L'équipe relit le code, traque les bugs et fait respecter les conventions. Quand on écrit du code à plusieurs, il faut définir des conventions communes. Une définition du « code propre » que Brikman affectionne :
Si je regarde un fichier écrit par 10 ingénieurs différents, je devrais être quasiment incapable de distinguer quelle partie a été écrite par qui. Pour moi, c'est ça, le code propre. — Nick Dellamaggiore
Quelques conventions Terraform utiles à la plupart des équipes :
- Documentation : il n'existe pas de code auto-documenté. Le code dit quoi, jamais pourquoi. Chaque module mérite un
README(écrit en premier, avant le code — le Readme-Driven Development), des commentaires (préfixés#) qui n'expliquent pas ce que fait le code mais pourquoi, des paramètresdescriptionsur chaque variable, et du code d'exemple. - Tests automatisés : tout le chapitre 7 y est consacré. Le commentaire de revue le plus important reste : « comment l'as-tu testé ? »
- Disposition des fichiers (file layout) : la disposition détermine la façon dont l'état est stocké ; soyez attentif à l'isolation entre Stage et Prod.
- Guide de style : peu importe le débat espaces contre tabulations, ce qui compte est la cohérence. Terraform fournit
terraform fmt, à lancer dans un commit hook pour reformater automatiquement.
Tests automatisés : toujours plan avant apply
Comme pour le code applicatif, des commit hooks doivent déclencher les tests automatisés sur un serveur de CI après chaque commit, et en afficher le résultat dans la pull request : tests unitaires, d'intégration, bout-en-bout, analyse statique. Mais il existe un test critique propre à l'infrastructure :
Astuce
Toujours lancer plan avant apply. Terraform affiche déjà le plan automatiquement au moment de l'apply ; la vraie règle est donc : marquez une pause et lisez la sortie du plan ! Trente secondes passées à scruter le « diff » évitent une quantité surprenante d'erreurs.
Un excellent moyen d'ancrer ce réflexe est d'intégrer plan dans le flux de revue. Atlantis, outil open source, lance automatiquement terraform plan sur les commits et ajoute la sortie en commentaire de la pull request. On peut aussi sauvegarder le diff dans un fichier, puis appliquer exactement ce plan :
$ terraform plan -out=example.plan
$ terraform apply example.plan Piège courant
Comme le fichier d'état, un fichier de plan sauvegardé peut contenir des secrets (par exemple le mot de passe d'une base de données). Ces fichiers n'étant pas chiffrés, si vous devez les conserver, fournissez votre propre chiffrement.
Fusionner et releaser
Une fois la revue faite, le plan validé et les tests au vert, on fusionne dans master et l'on release. Comme pour le code applicatif, on crée une version avec un tag Git :
$ git tag -a "v0.0.6" -m "Updated hello-world-example text"
$ git push --follow-tags Différence majeure : là où le code applicatif produit un artefact distinct (image Docker, image de VM), Terraform sait télécharger nativement du code depuis Git. Le dépôt à un tag précis est donc lui-même l'artefact immuable et versionné que vous allez déployer.
Déployer
Pour déployer du code Terraform, l'outil principal est Terraform lui-même, parfois épaulé par Atlantis, Terraform Enterprise, Terragrunt, ou des scripts. Mais attention :
Attention
Terraform n'offre aucune stratégie de déploiement intégrée (ni rolling, ni blue-green, ni feature toggle — on ne « feature toggle » pas une suppression de base de données). Et surtout, Terraform ne fait pas de rollback automatique en cas d'erreur : si un apply échoue après avoir supprimé une base ou détruit un serveur, on ne revient pas en arrière d'un claquement de doigts. Les erreurs étant relativement courantes, votre outillage doit les traiter comme la norme.
Trois familles d'erreurs à gérer en première classe :
- Réessais (retries) : certaines erreurs sont transitoires et disparaissent au prochain
apply. Terragrunt sait réessayer automatiquement sur les erreurs connues. - Erreurs d'état : si Terraform échoue à sauvegarder l'état (perte de connexion en plein
apply), il l'écrit sur disque danserrored.tfstate. Veillez à ce que votre serveur de CI ne supprime pas ce fichier ; une fois la connexion rétablie, poussez-le avecterraform state push errored.tfstate. - Verrous bloqués : si le serveur de CI plante au milieu d'un
apply, l'état reste verrouillé en permanence. Si vous êtes certain qu'il s'agit d'un verrou résiduel, libérez-le avecterraform force-unlock <LOCK_ID>.
Comme pour le code applicatif, tout déploiement doit s'exécuter depuis un serveur de CI, jamais depuis un poste de développeur. Mais les permissions sont ici bien plus délicates : pour une appli, le serveur de CI a besoin de quelques permissions ec2 et autoscaling fixes ; pour déployer du code d'infrastructure arbitraire (une base, un VPC, voire un nouveau compte AWS), il lui faut des permissions d'administrateur. Or les serveurs de CI, conçus pour exécuter du code arbitraire, sont difficiles à sécuriser. Pour limiter le risque : ne pas exposer le serveur de CI sur l'internet public (le placer en sous-réseaux privés, accessible par VPN, et le faire interroger le système de gestion de version par polling), le verrouiller (HTTPS uniquement, authentification, durcissement), et ne pas lui donner d'identifiants admin permanents — lui octroyer des identifiants temporaires (expirant après une heure) qu'un administrateur humain fournit pour les changements sensibles.
Le pipeline de déploiement de l'infrastructure
Reste à promouvoir vos artefacts immuables et versionnés d'un environnement à l'autre — par exemple v0.0.6 de Dev vers Stage vers Prod. La règle est simple :
À retenir
Toujours tester un changement Terraform en pré-production avant la production. Comme tout est automatisé, cela ne coûte presque rien de tester en Staging avant Prod, mais cela rattrape un nombre énorme d'erreurs. C'est d'autant plus important que Terraform ne fait pas de rollback : si un apply échoue, vous devez le réparer vous-même — plus facile et moins stressant à faire en pré-prod qu'en prod.
Le processus de promotion ressemble à celui des artefacts applicatifs, avec une étape de plus : exécuter terraform plan et examiner manuellement la sortie. Cette étape est rarement nécessaire pour le code applicatif (déploiements similaires, à faible risque), mais chaque déploiement d'infrastructure peut être radicalement différent, et une erreur peut coûter très cher (supprimer une base). Une dernière chance de relire le diff vaut largement le temps qu'elle prend. Voici le pipeline pour promouvoir, par exemple, v0.0.6 d'un module à travers Dev, Stage et Prod :
Pipeline de déploiement de l'infrastructure
pull request ──► terraform plan (automatique, Atlantis)
│
▼
diff posté en commentaire de la PR
│
revue humaine du diff
+ approbation (ex. message Slack)
│
merge sur master ◄── une seule branche par env partagé
│
▼
terraform apply (depuis le serveur de CI, permissions admin)
│
┌─────────────────┼──────────────────┐
▼ ▼ ▼
1) DEV 2) STAGE 3) PROD
plan → approve (idem 1) (idem 1)
→ apply → tests après succès Dev après succès Stage
On promeut le MÊME artefact v0.0.6 d'un environnement au suivant. Concrètement, pour chaque environnement : on met à jour vers v0.0.6 et l'on lance terraform plan ; on sollicite une approbation humaine du plan (par exemple un message automatique via Slack) ; si le plan est approuvé, on déploie par terraform apply ; on exécute les tests manuels et automatisés. Si tout va bien en Dev, on répète pour Staging, puis pour Production.
Garder le repo live DRY avec Terragrunt
Un problème pratique demeure : la duplication de code entre environnements dans le repo live. Même si chaque dossier ne fait qu'instancier un module du repo modules, il reste un volume important de code répété — la configuration du provider, la configuration du backend, le passage de toutes les variables d'entrée et la déclaration de toutes les sorties. Cela peut représenter des dizaines ou des centaines de lignes quasi identiques copiées-collées dans chaque environnement.
Pour rendre ce code plus DRY et faciliter la promotion, on peut utiliser Terragrunt, une fine surcouche (thin wrapper) open source de Terraform. Une fois installé, on lance les commandes Terraform habituelles en remplaçant le binaire par terragrunt. L'idée : définir le code Terraform exactement une fois dans le repo modules, et n'avoir dans le repo live que des fichiers terragrunt.hcl qui configurent et déploient chaque module dans chaque environnement.
On ajoute d'abord aux modules une configuration de provider et un bloc backend en configuration partielle (le reste sera rempli par Terragrunt) :
terraform {
# Require any 0.12.x version of Terraform
required_version = ">= 0.12, < 0.13"
# Partial configuration. The rest will be filled in by Terragrunt.
backend "s3" {}
} Dans le repo live, on supprime tous les fichiers .tf et on les remplace par un terragrunt.hcl par module. Ces fichiers utilisent la même syntaxe HCL que Terraform. Quand Terragrunt trouve le paramètre source, il récupère le module à l'URL indiquée (avec la version via ref) dans un dossier temporaire, puis y lance terraform apply en lui passant le bloc inputs :
terraform {
source = "github.com/<OWNER>/modules//data-stores/mysql?ref=v0.0.7"
}
include {
path = find_in_parent_folders()
}
inputs = {
db_name = "example_stage"
db_username = "admin"
# Set the password using the TF_VAR_db_password environment variable
} Terragrunt garde aussi la configuration du backend DRY. Plutôt que de redéfinir le bucket, la key et la dynamodb_table dans chaque module, on les définit une seule fois par environnement dans un terragrunt.hcl racine. La key y utilise la fonction path_relative_to_include(), qui renvoie le chemin relatif entre ce fichier racine et le module enfant :
remote_state {
backend = "s3"
config = {
bucket = "<YOUR_BUCKET>"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-2"
encrypt = true
dynamodb_table = "<YOUR_TABLE>"
}
} Le bloc include du module enfant retrouve ce fichier racine via find_in_parent_folders() et hérite automatiquement de tous ses réglages, dont la configuration remote_state. La key se résout alors d'elle-même en data-stores/mysql/terraform.tfstate : l'état est stocké dans la même arborescence que le repo live, ce qui rend limpide quel module a produit quel fichier d'état. Au déploiement, terragrunt apply lit le fichier, télécharge le module, lance terraform init (créant au besoin le bucket S3 et la table DynamoDB), puis terraform apply. Le repo live se réduit ainsi à un seul terragrunt.hcl par module : un pointeur vers le module à une version donnée, plus les variables d'entrée propres à l'environnement. À peu près aussi DRY qu'on puisse l'être.
Tout assembler
Vous savez désormais conduire le code applicatif et le code d'infrastructure du développement jusqu'à la production. Le tableau ci-dessous récapitule les deux workflows en vis-à-vis.
| Étape | Code applicatif | Code d'infrastructure |
|---|---|---|
| Gestion de version | git clone ; un repo par appli ; branches | git clone ; repos live et modules ; pas de branches |
| Exécuter en local | sur localhost (ruby web-server.rb) | dans un sandbox (terraform apply, go test) |
| Modifier le code | changer → rejouer les tests | changer → terraform apply, go test, test stages |
| Soumettre à la revue | pull request + conventions | pull request + conventions |
| Tests automatisés | unit, intégration, e2e, analyse statique (CI) | idem + terraform plan (CI) |
| Fusionner & releaser | git tag → artefact immuable | git tag → le repo au tag est l'artefact |
| Déployer | nombreuses stratégies ; CI à permissions limitées | stratégies limitées, gérer les erreurs (errored.tfstate) ; CI à permissions admin |
| Promouvoir | même artefact d'un env à l'autre | même artefact d'un env à l'autre |
En suivant ce processus, vous exécutez, testez, relisez et empaquetez code applicatif et infrastructure en artefacts immuables et versionnés, puis vous les promouvez d'environnement en environnement.
Conclusion du livre
Arrivé à ce point, vous savez à peu près tout ce qu'il faut pour utiliser Terraform dans la vraie vie : écrire du code Terraform, gérer l'état, créer des modules réutilisables, faire des boucles, des conditions et des déploiements, écrire du code de qualité production, le tester, et l'utiliser en équipe. Vous avez déployé serveurs, clusters, load balancers, bases de données, actions planifiées, alarmes CloudWatch, utilisateurs IAM, déploiements sans interruption et tests automatisés. N'oubliez pas de lancer terraform destroy dans chaque module quand vous avez terminé !
La puissance de Terraform, et plus généralement de l'IaC, c'est de pouvoir gérer toutes les préoccupations opérationnelles autour d'une application avec les mêmes principes de génie logiciel que l'application elle-même : modules, revues de code, gestion de version, tests automatisés. Utilisé correctement, Terraform permet à votre équipe de déployer plus vite et de réagir plus rapidement aux changements. Idéalement, les déploiements deviendront routiniers et ennuyeux — et en exploitation, l'ennui est une très bonne chose. Et si vous faites vraiment bien votre travail, plutôt que de passer tout votre temps à gérer l'infrastructure à la main, votre équipe pourra consacrer de plus en plus de temps à l'améliorer, pour aller encore plus vite.
À retenir
- Adopter l'IaC est autant culturel que technique : convainquez votre hiérarchie en parlant de ses problèmes (et non des fonctionnalités de Terraform), avancez de façon incrémentale pour que chaque étape ait sa propre valeur, et donnez à toute l'équipe le temps d'apprendre — sinon, à la première panne, on revient au manuel et la dérive s'installe.
- Le workflow applicatif et le workflow d'infrastructure se ressemblent en surface, mais l'infrastructure n'a pas de localhost (testez en sandbox), ses tests sont plus lents (utilisez les test stages), et le repo au tag Git sert lui-même d'artefact immuable.
- Séparez repo modules (bibliothèque réutilisable, versionnée, testée, façon catalogue de services) et repo live (l'infrastructure réellement déployée par environnement, un dossier par environnement).
- Règle d'or de Terraform : la branche
masterdu repo live est une représentation 1:1 de la production. Donc aucun changement hors-bande, pas de workspaces pour les environnements, et une seule branche par environnement partagé — car les branches et Terraform font mauvais ménage (leplann'a de sens que contre l'état réel). - Toujours
planavantapply, et intégrer leplanà la revue (Atlantis le poste en commentaire de la PR). Le pipeline type :planautomatique sur la pull request → revue et approbation humaine du diff →applyau merge surmaster, depuis un serveur de CI (jamais un poste de dev). - Terraform ne fait pas de rollback et offre des stratégies de déploiement limitées : traitez les erreurs en première classe (retries,
errored.tfstate,force-unlock), donnez au CI des permissions admin maîtrisées, et testez toujours en pré-prod avant la prod. - Promouvez le même artefact versionné d'un environnement à l'autre (Dev → Stage → Prod), et gardez le repo live DRY avec Terragrunt (un
terragrunt.hclpar module : un pointeur vers le module à une version, plus lesinputs, plus un backend hérité du fichier racine).