
Un projet Terraform bien organisé se structure en fichiers par responsabilité : versions.tf pour les providers, variables.tf pour les entrées, outputs.tf pour les sorties, et un ou plusieurs fichiers de ressources (network.tf, storage.tf…). Cette convention, utilisée par HashiCorp et la communauté, permet à n’importe quel contributeur d’ouvrir un projet et de savoir immédiatement où trouver chaque élément.
Prérequis : savoir écrire une configuration de base avec resource, variable et output. Avoir lu Séparer dev, staging et prod pour comprendre la structure modules + environnements.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Identifier les fichiers standard d’un projet Terraform et leur rôle
- Découper un fichier monolithique en fichiers par responsabilité
- Vérifier que le découpage ne casse rien avec
terraform validate - Formater automatiquement le code avec
terraform fmt - Configurer le
.gitignorepour ne versionner que l’utile
Le problème : le fichier monolithique
Section intitulée « Le problème : le fichier monolithique »Un projet Terraform débute souvent par un seul main.tf qui contient tout : providers, variables, ressources et outputs. À 50 lignes, c’est lisible. À 200 lignes, c’est pénible. À 500 lignes, c’est ingérable.
Voici un exemple de fichier monolithique de 100 lignes :
mon-projet/└── main.tf ← tout est ici : providers, variables, 3 ressources, outputsLe problème n’est pas technique (Terraform s’en moque), mais humain :
- Impossible de scanner rapidement : où sont les variables ? les outputs ?
- Conflits Git fréquents : deux personnes modifient le même fichier
- Revues de code pénibles : il faut lire 100 lignes pour trouver le changement
Les fichiers standard
Section intitulée « Les fichiers standard »Terraform charge automatiquement tous les fichiers .tf d’un répertoire. L’organisation en fichiers est une convention pour les humains, pas une contrainte technique.
| Fichier | Contenu | Obligatoire ? |
|---|---|---|
versions.tf | Bloc terraform {} (version requise, providers), bloc provider {} | Oui |
backend.tf | Backend distant ou configuration de state dédiée à l’environnement | Si backend distant |
variables.tf | Toutes les variable {} | Oui |
outputs.tf | Tous les output {} | Oui |
main.tf | Ressources principales (si projet simple) | Selon la taille |
network.tf | Ressources réseau | Selon le domaine |
storage.tf | Ressources stockage | Selon le domaine |
compute.tf | VMs, instances | Selon le domaine |
locals.tf | Bloc locals {} | Si nécessaire |
data.tf | Blocs data {} (data sources) | Si nécessaire |
terraform.tfvars | Valeurs par défaut des variables | Optionnel |
.gitignore | Fichiers à exclure du versionnement | Oui |
Du monolithe aux fichiers séparés
Section intitulée « Du monolithe aux fichiers séparés »-
Extraire versions.tf
Déplacez le bloc
terraform {}et le blocprovider {}dansversions.tf:versions.tf terraform {required_version = ">= 1.11.0"required_providers {libvirt = {source = "dmacvicar/libvirt"version = "~> 0.8"}}}provider "libvirt" {uri = "qemu:///system"} -
Extraire variables.tf
Regroupez toutes les déclarations
variable {}:variables.tf variable "env_name" {description = "Nom de l'environnement"type = stringdefault = "demo"}variable "base_image_path" {description = "Chemin vers l'image de base"type = stringdefault = "/chemin/vers/image.qcow2"} -
Séparer les ressources par domaine
Un fichier par domaine de responsabilité :
# network.tf — tout ce qui touche au réseauresource "libvirt_network" "main" {name = "${var.env_name}-network"autostart = trueforward = {mode = "nat"}dns = {enabled = true}ips = [{address = "10.10.80.1"netmask = "255.255.255.0"dhcp = {ranges = [{start = "10.10.80.10"end = "10.10.80.100"}]}}]}# storage.tf — tout ce qui touche aux volumesresource "libvirt_volume" "system" {name = "${var.env_name}-system.qcow2"pool = "default"backing_store = {path = var.base_image_pathformat = { type = "qcow2" }}target = {format = { type = "qcow2" }}capacity = 4 * 1024 * 1024 * 1024}resource "libvirt_volume" "data" {name = "${var.env_name}-data.qcow2"pool = "default"target = {format = { type = "qcow2" }}capacity = 8 * 1024 * 1024 * 1024} -
Extraire outputs.tf
outputs.tf output "network_name" {description = "Nom du réseau"value = libvirt_network.main.name}output "system_volume" {description = "Chemin du volume système"value = libvirt_volume.system.id}output "data_volume" {description = "Chemin du volume données"value = libvirt_volume.data.id} -
Valider le découpage
Terraform doit produire exactement le même plan qu’avant le découpage :
Fenêtre de terminal terraform validateSuccess! The configuration is valid.Le découpage est une opération sans risque : si
validatepasse, le plan sera identique.
Le résultat après découpage :
mon-projet/├── versions.tf 14 lignes — providers├── variables.tf 11 lignes — entrées├── network.tf 23 lignes — réseau├── storage.tf 32 lignes — stockage└── outputs.tf 14 lignes — sortiesChaque fichier fait moins de 35 lignes et a une responsabilité claire. Ouvrir network.tf montre immédiatement la configuration réseau, sans bruit.
Formater avec terraform fmt
Section intitulée « Formater avec terraform fmt »Terraform fournit un formateur intégré qui aligne les =, indente correctement et normalise les espaces.
Vérifier sans modifier
Section intitulée « Vérifier sans modifier »Le mode --check signale les fichiers mal formatés sans les toucher :
terraform fmt -checkSi un fichier est mal formaté, Terraform affiche son nom et renvoie un code de sortie non-zéro — utile en CI/CD.
Voir les corrections
Section intitulée « Voir les corrections »Le mode -diff montre ce qui serait modifié :
terraform fmt -diff--- old/variables.tf+++ new/variables.tf@@ -1,11 +1,11 @@ variable "env_name" {-description="Nom de l'environnement"- type=string- default = "demo"+ description = "Nom de l'environnement"+ type = string+ default = "demo" }
variable "base_image_path" {- description = "Chemin vers l'image de base"-type = string+ description = "Chemin vers l'image de base"+ type = string }Appliquer le formatage
Section intitulée « Appliquer le formatage »Sans option, terraform fmt corrige les fichiers directement :
terraform fmtLe .gitignore Terraform
Section intitulée « Le .gitignore Terraform »Certains fichiers et répertoires ne doivent jamais être versionnés :
# Répertoire des plugins téléchargés (volumineux, recréé par terraform init).terraform/
# State local (contient des données sensibles)*.tfstate*.tfstate.*
# Fichiers de sauvegarde*.backup
# Variables sensibles (mots de passe, tokens)*.auto.tfvarssecrets.tfvars
# Fichiers de crash Terraformcrash.logcrash.*.log
# Fichiers de plan (binaires)*.tfplan
# Fichiers générés par override (usage avancé)override.tfoverride.tf.json*_override.tf*_override.tf.jsonStructure complète recommandée
Section intitulée « Structure complète recommandée »Pour un projet avec modules et environnements (en combinant les conventions vues dans les guides précédents) :
mon-projet/├── .gitignore├── .terraform.lock.hcl ← Versionné !├── README.md├── modules/│ └── reseau/│ ├── versions.tf│ ├── variables.tf│ ├── main.tf│ └── outputs.tf└── envs/ ├── dev/ │ ├── backend.tf │ ├── versions.tf │ ├── main.tf ← Appelle le module │ ├── outputs.tf │ └── terraform.tfvars ├── staging/ │ ├── backend.tf │ ├── versions.tf │ ├── main.tf │ ├── outputs.tf │ └── terraform.tfvars └── prod/ ├── backend.tf ├── versions.tf ├── main.tf ├── outputs.tf └── terraform.tfvarsLes erreurs courantes
Section intitulée « Les erreurs courantes »| Erreur | Pourquoi c’est un problème | Solution |
|---|---|---|
main.tf de plus de 200 lignes | Illisible, conflits Git, revues pénibles | Découper par domaine (network.tf, storage.tf…) |
Variables déclarées dans main.tf | Impossible de les trouver rapidement | Toujours dans variables.tf |
Provider dans main.tf | Mélange providers/ressources | Toujours dans versions.tf |
.terraform/ versionné | Répertoire volumineux, spécifique à la machine | Ajouter .terraform/ au .gitignore |
.terraform.lock.hcl dans .gitignore | Versions de providers différentes selon les machines | Retirer du .gitignore, versionner |
terraform.tfstate versionné | Données sensibles exposées dans Git | Ajouter *.tfstate au .gitignore + utiliser un backend distant |
Fichiers nommés au hasard (infra.tf, stuff.tf) | Aucune convention reconnaissable | Utiliser les noms standards de la communauté |
À retenir
Section intitulée « À retenir »- Un fichier par responsabilité : versions.tf, variables.tf, outputs.tf, et des fichiers de ressources par domaine
backend.tfmérite son propre fichier dès que vous utilisez un backend distant ou une configuration différente selon l’environnement- Le découpage est sans risque :
terraform validateconfirme que le plan reste identique terraform fmtformate automatiquement le code — à utiliser en CI/CD et pre-commit- Le
.terraform.lock.hclse versionne, le.terraform/et les*.tfstatenon - Ces conventions permettent à n’importe qui d’ouvrir un projet Terraform et de s’y retrouver immédiatement