Aller au contenu
Infrastructure as Code medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Versionner ses modules Terraform avec Git

11 min de lecture

logo terraform

Versionner un module Terraform consiste à associer un tag Git sémantique à chaque version stable du code. Cela permet aux projets consommateurs de choisir précisément quelle version utiliser, d’éviter les régressions et de planifier les mises à jour. Sans versionnement, modifier un module impacte immédiatement tous les projets qui le consomment.

Prérequis : avoir lu Utiliser un module local et Utiliser un module du Registry.

  • Comprendre pourquoi le versionnement est indispensable
  • Appliquer le versionnement sémantique (SemVer) aux modules
  • Créer des tags Git pour versionner un module
  • Référencer une version spécifique depuis un projet consommateur
  • Mettre à jour un module de façon contrôlée

Avec un module local (source = "../modules-partages/reseau"), toute modification du module est immédiatement visible par tous les projets qui le consomment. Cela signifie qu’un changement dans le module peut casser un projet en production sans prévenir.

modules-partages/reseau/ ← une modification ici...
├── projet-dev/ ← ...impacte ici
├── projet-staging/ ← ...et ici
└── projet-prod/ ← ...et ici aussi !

Le versionnement découple le rythme de développement du module du rythme d’adoption par les projets. Chaque projet choisit quand monter en version :

module "reseau" {
source = "git::https://gitlab.example.com/infra/modules.git//reseau?ref=v1.2.0"
# ↑ ce projet utilise la v1.2.0 — il ne sera pas impacté par des changements ultérieurs
}

Le standard utilisé par Terraform et le Registry est le Semantic Versioning (SemVer) : MAJOR.MINOR.PATCH.

ComposantQuand l’incrémenterExemple
MAJORChangement incompatible (breaking change)1.0.02.0.0
MINORNouvelle fonctionnalité rétrocompatible1.0.01.1.0
PATCHCorrection de bug rétrocompatible1.0.01.0.1
ModificationTypeVersion
Corriger le message d’erreur d’une validationPATCH1.0.01.0.1
Ajouter une variable optionnelle tags avec default = {}MINOR1.0.11.1.0
Renommer cidr en network_config (breaking)MAJOR1.1.02.0.0
Supprimer une variable existanteMAJOR1.1.02.0.0
Ajouter un nouvel outputMINOR1.1.01.2.0
  1. Initialiser un dépôt Git pour les modules :

    Fenêtre de terminal
    cd modules-partages/
    git init
    git add .
    git commit -m "feat: module réseau initial"
  2. Créer un tag pour la première version :

    Fenêtre de terminal
    git tag -a v1.0.0 -m "Version initiale du module réseau"
    git push origin v1.0.0
  3. Après une modification mineure (ajout d’une variable optionnelle) :

    Fenêtre de terminal
    # Modifier le code...
    git add .
    git commit -m "feat(reseau): ajouter variable tags optionnelle"
    git tag -a v1.1.0 -m "Ajout de la variable tags"
    git push origin v1.1.0
  4. Après un breaking change (renommage de variable) :

    Fenêtre de terminal
    # Modifier le code...
    git add .
    git commit -m "BREAKING CHANGE(reseau): renommer cidr en network_config"
    git tag -a v2.0.0 -m "Renommage cidr → network_config"
    git push origin v2.0.0
module "reseau" {
source = "git::https://gitlab.example.com/infra/modules.git//reseau?ref=v1.2.0"
# ↑ URL Git ↑ chemin du module dans le dépôt ↑ tag Git
}

La syntaxe ?ref=v1.2.0 fige la version. Même si de nouvelles versions sont publiées, ce projet reste sur v1.2.0.

ref peut pointer vers un tag, une branche ou un commit SHA, mais pour un module partagé entre équipes, un tag Git sémantique reste le choix le plus lisible et le plus sûr.

module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.21.0"
# ↑ contrainte de version gérée par le Registry
}

Les mêmes contraintes que pour les providers s’appliquent :

version = "1.2.0" # exactement 1.2.0
version = "~> 1.2.0" # >= 1.2.0 et < 1.3.0 (patchs uniquement)
version = "~> 1.2" # >= 1.2.0 et < 2.0.0 (évolutions compatibles de la même majeure)
version = ">= 1.0, < 2.0" # plage explicite
ContrainteRecommandationCas d’usage
"1.2.0"ProductionReproductibilité maximale
"~> 1.2.0"StagingRecevoir les patchs automatiquement
"~> 1.2"DéveloppementRecevoir les évolutions compatibles de la même majeure

Quand une nouvelle version d’un module est disponible, chaque projet décide quand l’adopter :

  1. Lire le changelog de la nouvelle version pour identifier les changements

  2. Mettre à jour la contrainte de version dans le bloc module :

    module "reseau" {
    source = "git::https://gitlab.example.com/infra/modules.git//reseau?ref=v1.3.0"
    # ↑ v1.2.0 → v1.3.0
    }
  3. Relancer terraform init pour télécharger la nouvelle version :

    Fenêtre de terminal
    terraform init -upgrade
    # -upgrade force le re-téléchargement même si une version est déjà en cache
  4. Exécuter terraform plan pour voir les changements prévus :

    Fenêtre de terminal
    terraform plan
    # Vérifier qu'aucune destruction inattendue n'apparaît
  5. Appliquer si le plan est correct

Pour un dépôt Git contenant plusieurs modules, la convention est :

terraform-modules/
├── reseau/
│ ├── versions.tf
│ ├── variables.tf
│ ├── main.tf
│ └── outputs.tf
├── volume/
│ ├── versions.tf
│ ├── variables.tf
│ ├── main.tf
│ └── outputs.tf
├── vm/
│ └── ...
├── CHANGELOG.md
└── README.md

Le tag versionne tout le dépôt. Si les modules évoluent à des rythmes différents, deux approches existent :

ApprocheAvantageInconvénient
Mono-dépôt (1 tag pour tout)Simple à gérerUn changement dans reseau/ force un nouveau tag même si vm/ n’a pas changé
Multi-dépôts (1 dépôt par module)Versionnement indépendantPlus de dépôts à maintenir

Pour commencer, le mono-dépôt est recommandé. Passez au multi-dépôts quand les modules évoluent à des rythmes très différents.

Un fichier CHANGELOG.md à la racine du dépôt de modules documente l’historique des versions :

# Changelog
## [1.2.0] - 2025-03-31
### Added
- Variable `tags` optionnelle sur le module réseau
## [1.1.0] - 2025-03-15
### Added
- Output `configuration` structuré sur le module réseau
## [1.0.0] - 2025-03-01
### Added
- Module réseau initial (libvirt_network)

Ce format suit la convention Keep a Changelog.

SymptômeCause probableSolution
terraform init ne télécharge pas la nouvelle versionVersion en cacheAjouter -upgrade à terraform init
ref not found avec source GitTag inexistant ou faute de frappeVérifier avec git tag -l sur le dépôt
Changements inattendus après mise à jourBreaking change non documentéRevenir à l’ancienne version et lire le changelog
version ... does not match (Registry)Contrainte trop restrictiveÉlargir la contrainte ou spécifier la version exacte
  1. Sans versionnement, modifier un module impacte immédiatement tous les projets
  2. Le versionnement sémantique (MAJOR.MINOR.PATCH) communique la nature du changement
  3. Tout changement qui oblige à modifier le bloc module est un breaking change (MAJOR)
  4. Les tags Git annotés (git tag -a) sont le mécanisme de versionnement
  5. ?ref=vX.Y.Z (Git) ou version = "X.Y.Z" (Registry) figent la version dans un projet
  6. -upgrade sur terraform init force le re-téléchargement d’une version
  7. Mettez à jour un environnement à la fois : dev → staging → prod

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn