Modules Terraform
Objectifs du chapitre
- Comprendre les modules
- Créer des modules réutilisables
- Utiliser le Terraform Registry
- Organiser un projet avec modules
1 - Qu'est-ce qu'un module ?
Définition
Un module est un conteneur pour plusieurs ressources utilisées ensemble.
Avantages
| Sans modules | Avec modules |
|---|---|
| Code dupliqué | Code réutilisable |
| Fichiers énormes | Composants isolés |
| Difficile à maintenir | Facile à tester |
| Pas de versioning | Versionnable |
2 - Structure d'un module
Arborescence standard
modules/
└── vpc/
├── main.tf # Ressources principales
├── variables.tf # Variables d'entrée
├── outputs.tf # Valeurs de sortie
├── versions.tf # Versions requises
└── README.md # Documentation
Module VPC exemple
# modules/vpc/variables.tf
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
}
variable "environment" {
description = "Environment name"
type = string
}
variable "availability_zones" {
description = "List of availability zones"
type = list(string)
}
# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.environment}-vpc"
Environment = var.environment
}
}
resource "aws_subnet" "public" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${var.environment}-public-${count.index + 1}"
}
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.environment}-igw"
}
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "${var.environment}-public-rt"
}
}
resource "aws_route_table_association" "public" {
count = length(var.availability_zones)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
# modules/vpc/outputs.tf
output "vpc_id" {
description = "ID of the VPC"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "IDs of public subnets"
value = aws_subnet.public[*].id
}
output "vpc_cidr" {
description = "CIDR block of the VPC"
value = aws_vpc.main.cidr_block
}
3 - Utiliser un module
Module local
# main.tf
module "vpc" {
source = "./modules/vpc"
vpc_cidr = "10.0.0.0/16"
environment = "production"
availability_zones = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
}
# Utiliser les outputs du module
resource "aws_instance" "web" {
subnet_id = module.vpc.public_subnet_ids[0]
# ...
}
# Re-exporter les outputs
output "vpc_id" {
value = module.vpc.vpc_id
}
Module depuis le Registry
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
tags = {
Environment = "production"
}
}
Module depuis Git
# GitHub
module "vpc" {
source = "github.com/myorg/terraform-modules//vpc?ref=v1.0.0"
}
# GitLab
module "vpc" {
source = "git::https://gitlab.com/myorg/terraform-modules.git//vpc?ref=v1.0.0"
}
# SSH
module "vpc" {
source = "[email protected]:myorg/terraform-modules.git//vpc?ref=v1.0.0"
}
4 - Sources de modules
Types de sources
Syntaxe
# Local
source = "./modules/vpc"
source = "../shared-modules/vpc"
# Terraform Registry
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
# GitHub
source = "github.com/hashicorp/example"
source = "github.com/hashicorp/example//subdir"
source = "github.com/hashicorp/example?ref=v1.2.0"
# S3
source = "s3::https://s3-eu-west-1.amazonaws.com/bucket/modules/vpc.zip"
# HTTP
source = "https://example.com/modules/vpc.zip"
5 - Versioning des modules
Registry versions
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0" # Exact
version = "~> 5.0" # >= 5.0.0, < 6.0.0
version = ">= 5.0, < 6.0" # Range
}
Git refs
# Tag
source = "github.com/org/repo?ref=v1.0.0"
# Branch
source = "github.com/org/repo?ref=develop"
# Commit
source = "github.com/org/repo?ref=abc1234"
6 - Modules imbriqués
Composition
Passer des outputs entre modules
# root/main.tf
module "vpc" {
source = "./modules/vpc"
vpc_cidr = var.vpc_cidr
environment = var.environment
}
module "ec2" {
source = "./modules/ec2"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.public_subnet_ids
instance_count = var.instance_count
}
module "rds" {
source = "./modules/rds"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
allowed_sg_ids = [module.ec2.security_group_id]
}
7 - Modules count et for_each
count
module "web_cluster" {
source = "./modules/ec2-cluster"
count = var.create_cluster ? 1 : 0
instance_count = 3
instance_type = "t3.micro"
}
# Accès
output "cluster_ips" {
value = var.create_cluster ? module.web_cluster[0].instance_ips : []
}
for_each
variable "environments" {
default = {
dev = {
instance_type = "t3.micro"
instance_count = 1
}
staging = {
instance_type = "t3.small"
instance_count = 2
}
production = {
instance_type = "t3.large"
instance_count = 3
}
}
}
module "env" {
source = "./modules/environment"
for_each = var.environments
environment = each.key
instance_type = each.value.instance_type
instance_count = each.value.instance_count
}
# Accès
output "env_vpc_ids" {
value = { for k, v in module.env : k => v.vpc_id }
}
8 - Terraform Registry
Modules publics populaires
| Provider | Module | Description |
|---|---|---|
| AWS | terraform-aws-modules/vpc/aws | VPC complet |
| AWS | terraform-aws-modules/eks/aws | Cluster EKS |
| AWS | terraform-aws-modules/rds/aws | Base de données RDS |
| Azure | Azure/network/azurerm | Virtual Network |
| GCP | terraform-google-modules/network/google | VPC Network |
Exemple EKS
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "19.0.0"
cluster_name = "my-cluster"
cluster_version = "1.28"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
eks_managed_node_groups = {
default = {
min_size = 1
max_size = 3
desired_size = 2
instance_types = ["t3.medium"]
}
}
tags = {
Environment = "production"
}
}
9 - Publier un module
Structure pour le Registry
terraform-aws-my-module/
├── main.tf
├── variables.tf
├── outputs.tf
├── versions.tf
├── README.md
├── LICENSE
├── examples/
│ ├── simple/
│ │ ├── main.tf
│ │ └── README.md
│ └── complete/
│ ├── main.tf
│ └── README.md
└── modules/
└── submodule/
├── main.tf
├── variables.tf
└── outputs.tf
Requirements
✅ Repo public sur GitHub
✅ Nommé terraform-<PROVIDER>-<NAME>
✅ README.md avec description
✅ LICENSE
✅ Tags Git pour versioning (v1.0.0)
✅ Structure standard
10 - Bonnes pratiques
Structure
# ✅ Fichiers séparés
# main.tf - Ressources
# variables.tf - Variables d'entrée
# outputs.tf - Valeurs de sortie
# versions.tf - Contraintes de version
Variables
# ✅ Description et type pour toutes les variables
variable "instance_type" {
description = "Type d'instance EC2"
type = string
default = "t2.micro"
}
# ✅ Validation
variable "environment" {
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
Documentation
# Module VPC
Creates a VPC with public and private subnets.
## Usage
```hcl
module "vpc" {
source = "./modules/vpc"
vpc_cidr = "10.0.0.0/16"
environment = "production"
}
Inputs
| Name | Description | Type | Default |
|---|---|---|---|
| vpc_cidr | CIDR block for VPC | string | - |
| environment | Environment name | string | - |
Outputs
| Name | Description |
|---|---|
| vpc_id | ID of the VPC |
---
## Résumé
```mermaid
mindmap
root((Modules))
Sources
Local
Registry
Git
Structure
main.tf
variables.tf
outputs.tf
Réutilisation
count
for_each
Registry
Publics
Privés
Points clés
- Les modules encapsulent des ressources liées
- Utilisez des versions pour la stabilité
- Le Registry offre des modules prêts à l'emploi
- Documentez toujours vos modules
- Testez avec des exemples
Exercices pratiques
- Créez un module VPC avec subnets publics et privés
- Utilisez un module du Registry (terraform-aws-modules/vpc/aws)
- Créez un module appelant d'autres modules
- Publiez un module sur un repo Git