Aller au contenu principal

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 modulesAvec modules
Code dupliquéCode réutilisable
Fichiers énormesComposants isolés
Difficile à maintenirFacile à tester
Pas de versioningVersionnable

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

ProviderModuleDescription
AWSterraform-aws-modules/vpc/awsVPC complet
AWSterraform-aws-modules/eks/awsCluster EKS
AWSterraform-aws-modules/rds/awsBase de données RDS
AzureAzure/network/azurermVirtual Network
GCPterraform-google-modules/network/googleVPC 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

NameDescriptionTypeDefault
vpc_cidrCIDR block for VPCstring-
environmentEnvironment namestring-

Outputs

NameDescription
vpc_idID 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

  1. Créez un module VPC avec subnets publics et privés
  2. Utilisez un module du Registry (terraform-aws-modules/vpc/aws)
  3. Créez un module appelant d'autres modules
  4. Publiez un module sur un repo Git

← State Management | Bonnes pratiques →