Patterns de modules avances 25 min de lecture

Design et composition de modules

Principes de design de modules

Un bon module Terraform suit ces principes :

  • Single responsibility — Un module fait une seule chose bien
  • Encapsulation — Les details d'implementation sont caches
  • Composabilite — Les modules peuvent se combiner
  • Reusabilite — Le module fonctionne dans differents contextes

Structure standard d'un module

modules/vpc/
  main.tf          # Ressources principales
  variables.tf     # Variables d'entree
  outputs.tf       # Valeurs de sortie
  versions.tf      # Contraintes de version
  README.md        # Documentation

Module avec validation des variables

variable "environment" {
  type        = string
  description = "Environnement de deploiement"

  validation {
    condition     = contains(["dev", "staging", "production"], var.environment)
    error_message = "L'environnement doit etre dev, staging ou production."
  }
}

variable "cidr_block" {
  type        = string
  description = "CIDR du VPC"

  validation {
    condition     = can(cidrhost(var.cidr_block, 0))
    error_message = "Le CIDR doit etre valide (ex: 10.0.0.0/16)."
  }
}

Composition de modules

# Root module qui compose des sous-modules
module "vpc" {
  source      = "./modules/vpc"
  cidr_block  = "10.0.0.0/16"
  environment = var.environment
}

module "eks" {
  source     = "./modules/eks"
  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnet_ids
  depends_on = [module.vpc]
}

module "rds" {
  source     = "./modules/rds"
  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.database_subnet_ids
}

Module generique avec for_each et dynamic

variable "security_rules" {
  type = list(object({
    port        = number
    protocol    = string
    cidr_blocks = list(string)
  }))
}

resource "aws_security_group" "this" {
  name   = var.name
  vpc_id = var.vpc_id

  dynamic "ingress" {
    for_each = var.security_rules
    content {
      from_port   = ingress.value.port
      to_port     = ingress.value.port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }
}
Bonne pratique : Utilisez des types complexes (object, map) avec des validations pour rendre vos modules robustes et auto-documentes.