Aller au contenu

Step-1-4 : Les modules terraform

Lors de l'étape précédente, avec le découpage en plusieurs instances par service et l'ajout du VPC et de ses composants, notre plan est devenu beaucoup plus gros, moins lisible, pas très DRY et donc moins maintenable.

Durant cette nouvelle étape, nous allons voir comment organiser notre code Terraform via les modules pour essayer de résoudre ces problèmes.

Concepts

Les modules Terraform sont un rassemblement de plusieurs ressources utilisées ensemble. Un module est un ensemble de fichiers .tf dans un même répertoire.

Les modules sont le principal moyen de regrouper et de réutiliser les configurations de ressources avec Terraform.

Info

Chaque config a en fait un module qui est en fait le root module.

Les modules que l'on déclare et utilise dans notre configuration sont appellés modules enfants.

On peut référencer des modules déclarés dans un sous-dossier, mais également des modules stockés, versionnés et utilisés depuis une registry, on parle alors de Published Modules.

Published Modules

Les modules publiés sur le registry public permettent de ne pas réinventer la roue et de se servir de modules développés en Opensource.

Par exemple, un module VPC est maintenu par la communauté et permet simplement via des variables de créer un VPC, ses subnets, internet gateway, NAT gateway, NACLs, routes... Et oui 😅

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.5.2"

  ...
}

Comme toute dépendance que l'on va utiliser, il faut faire attention à son contenu, son utilisabilité, comment le code est maintenu, etc. Sur le long terme pour une bonne maintenance de notre code, il faut également suivre les évolutions faites sur le module, nouvelles versions, changelogs, upgrades guides, etc.

Modules locaux

S'il n'existe pas de module adapté à notre besoin et/ou que l'on souhaite developer nous même un module, nous pouvons faire des modules avec une source locale.

Un module s'utilise via un module block déclaré de cette façon :

module "instance_1" {
  source = "./instance"

  size = "t2.micro"
}

Les modules peuvent déclarer comme le module root des variables de la façon suivante :

variable "size" {
  type = string
}

Les modules peuvent aussi déclarer comme le module root des output de la façon suivante :

output "id" {
  value = module.instance_1.id
}

Et l'utilisation de l'output module se fait via la référence module.instance_1.id ici par exemple.

On peut ensuite si besoin utiliser les meta-arguments for_each et count avec le module.

Tip

Votre config peut également être paramétrée. Les valeurs sont données pour le plan ou l'apply via -var ou -var-file.

C'est d'ailleur de cette façon que l'on peut réutiliser un même plan pour plusieurs environnements.

Warning

Découper en module doit faire sens et simplifier les choses. Une nouvelle abstraction doit idéalemnet en sortir. Il n'est pas conseillé de juste faire des wrappers à une resource simple, plus d'info ici.

TP

À vous de jouer

Le but de cette étape est de simplifier et refactorer votre code afin de mieux le découper et l'organiser grâce aux modules.

  • Copiez votre dossier précédent Step1-3-2 en un nouveau dossier nommé Step1-4
  • Développez module local compute que vous utiliserez ensuite pour créer toutes vos instances
    • Une variable définira si le disque est présent
  • Réutilisez le module VPC pour gérer la stack network
    • Utilisez le single_nat_gateway = false pour éviter des coûts inutiles

Tip

Pour le paramétrage du disque plutôt qu'un simple booléen disk_enabled vous pouvez utiliser une variable plus complète

variable "devices" {
  description = "EBS disks that will be attached to the instance"
  type = set(object({
    size        = number
    encrypted   = bool
    disk_type   = bool
    device_name = string
  }))
  default = []
}

Success

Avec ce refactoring le code est plus maintenable !

Bonus

Réalisez un module security-group permettant de les déclarer également.

Note

Terraform permet d'implémenter des logiques de validation de variables via le mot clé validation.

Vous pouvez vous en servir ici pour valider si une des rules est mal déclarée, par exemple pour empêcher de déclarer à la fois un referenced_security_group_id et un cidr_ipv4 ce qui n'est pas autorisé.