Retour au cours

infra / terraform

Modules : créer et réutiliser

Leçon 71 exercice

Explication

Ce que vous allez apprendre

  • Structurer un module Terraform réutilisable avec ses propres variables et outputs
  • Appeler un même module plusieurs fois avec des paramètres différents
  • Référencer les sorties d'un module depuis la racine du projet
  • Utiliser un module public du Terraform Registry plutôt que d'en réécrire un
  • Savoir quand terraform get est nécessaire en plus de terraform init

Dans quel contexte ?

L'équipe doit déployer un serveur web et un serveur worker, tous deux des instances EC2 très similaires (même AMI, même groupe de sécurité de base), qui ne diffèrent que par leur nom et leur taille. Copier-coller le même bloc resource deux fois fonctionne, mais la moindre correction de sécurité devrait alors être répétée manuellement partout où ce bloc a été dupliqué.

D'abord, il faut comprendre ce qu'est réellement un module

Un module Terraform n'est rien de plus qu'un dossier contenant des fichiers .tf, structuré comme n'importe quel projet Terraform : un main.tf avec les ressources, un variables.tf pour ses entrées paramétrables, et un outputs.tf pour exposer ce qui doit être réutilisé à l'extérieur. Même la configuration racine d'un projet Terraform est, techniquement, un module — le "module racine".

Cette symétrie explique pourquoi un module se comporte, une fois appelé, presque comme une ressource ordinaire : il prend des entrées (variables) et produit des sorties (outputs).

FichierRôle dans un module
variables.tfEntrées paramétrables du module (ce que l'appelant doit fournir)
main.tfRessources créées par le module
outputs.tfSorties consultables par l'appelant du module

Prérequis

Une bonne maîtrise des blocs resource, variable et output (leçons précédentes) est indispensable : un module n'est qu'une façon d'organiser et de réutiliser ces mêmes briques.

Une fois le module écrit, comment l'utiliser concrètement ?

Un bloc module "nom_local" { source = "./modules/ec2-instance" ... } appelle le module en lui passant ses paramètres, exactement comme on passerait des arguments à une fonction. Rien n'empêche d'appeler le MÊME module plusieurs fois avec des paramètres différents — c'est exactement ce qui résout le problème de duplication posé en introduction.

Bonne pratique

Dès qu'un même schéma de ressources (une instance + son groupe de sécurité, par exemple) se répète plus de deux fois dans une configuration, c'est le signal qu'il devrait devenir un module. Cette règle simple évite à la fois la sur-ingénierie (module trop tôt, pour un usage unique) et la duplication incontrôlée.

Il reste une question de référencement : comment récupérer une sortie d'un module ?

Depuis la racine du projet, une sortie de module se référence avec le préfixe module.<nom_local>., exactement comme un attribut de ressource se référence avec type.nom.. Cette cohérence de syntaxe rend les modules faciles à composer les uns avec les autres.

Maintenant, une découverte qui change la donne : pas besoin de tout réécrire soi-même

Astuce

Le Terraform Registry héberge des milliers de modules communautaires, testés et versionnés, pour les besoins les plus courants — un VPC complet AWS (terraform-aws-modules/vpc/aws) en est l'exemple le plus utilisé au monde. Avant d'écrire un module depuis zéro pour un besoin standard, vérifie toujours si un module public de qualité existe déjà : réinventer un VPC complet représente des centaines de lignes de HCL déjà écrites, testées et maintenues par d'autres.

Le piège à connaître avant de continuer

Piège fréquent

Après avoir ajouté un nouveau module dans la configuration, terraform init seul suffit généralement, mais terraform get reste utile pour rafraîchir explicitement les modules sans relancer toute l'initialisation des providers — pratique lors d'itérations rapides sur un module en cours de développement.

Une fois les modules maîtrisés, la prochaine leçon explore les expressions et fonctions HCL qui permettent de rendre ces modules encore plus flexibles : boucles for, conditions, et génération dynamique de blocs.

Commandes & code

Modules : créer et réutiliser

bash
# Structure d'un module réutilisable "modules/ec2-instance/"
modules/ec2-instance/
├── main.tf          # ressources du module
├── variables.tf     # entrées du module
└── outputs.tf       # sorties du module
hcl
# modules/ec2-instance/variables.tf
variable "nom" {
  type = string
}
variable "instance_type" {
  type    = string
  default = "t3.micro"
}
variable "ami_id" {
  type = string
}

# modules/ec2-instance/main.tf
resource "aws_instance" "cette_instance" {
  ami           = var.ami_id
  instance_type = var.instance_type
  tags = {
    Name = var.nom
  }
}

resource "aws_security_group" "sg" {
  name = "${var.nom}-sg"
  # ... règles ingress/egress
}

# modules/ec2-instance/outputs.tf
output "instance_id" {
  value = aws_instance.cette_instance.id
}
output "ip_privee" {
  value = aws_instance.cette_instance.private_ip
}
hcl
# racine du projet : appel du module, deux fois avec des paramètres différents
module "serveur_web" {
  source        = "./modules/ec2-instance"
  nom           = "web-prod"
  instance_type = "t3.small"
  ami_id        = data.aws_ami.ubuntu_dernier.id
}

module "serveur_worker" {
  source        = "./modules/ec2-instance"
  nom           = "worker-prod"
  instance_type = "t3.medium"
  ami_id        = data.aws_ami.ubuntu_dernier.id
}

# Référencer une sortie d'un module depuis la racine : module.<nom>.<output>
output "ip_web" {
  value = module.serveur_web.ip_privee
}
hcl
# Modules provenant du Registry public (versionnés, testés par la communauté)
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.8.1"

  name = "vpc-prod"
  cidr = "10.0.0.0/16"

  azs             = ["eu-west-3a", "eu-west-3b"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]

  enable_nat_gateway = true
}
bash
terraform get                  # télécharge/actualise les modules référencés
terraform init                  # (télécharge aussi les modules au premier init)

Résumé

  • Un module est un dossier .tf réutilisable avec ses propres variables.tf/outputs.tf, appelé via module "nom" { source = ... }.
  • Le Terraform Registry héberge des modules communautaires versionnés (ex : terraform-aws-modules/vpc/aws), à préférer à réinventer un VPC complet.
  • Les sorties d'un module se référencent en préfixant module.<nom_local>..

Exercices pratiques

1 disponible
1

Mission : dupliquer un module sans dupliquer le code

Objectif : Réutiliser un module existant pour un nouveau besoin et raisonner sur l'encapsulation et le versionnage des modules.

Contexte

Le module ./modules/ec2-instance est déjà utilisé deux fois à la racine du projet, pour serveur_web et serveur_worker. L'équipe doit maintenant déployer un troisième serveur, serveur_scheduler, en t3.micro, sans dupliquer le contenu du module lui-même. Par ailleurs, le module public terraform-aws-modules/vpc/aws est appelé ailleurs dans le projet sans argument version.

Résoudre l’exercice →