Exercice 02 : Créer des ressources dynamiques avec for_each et count
🎯 Objectifs
À la fin de cet exercice, vous serez capable de :
- ✅ Créer N ressources similaires avec
count - ✅ Créer des ressources nommées avec
for_eachsur une map - ✅ Utiliser
each.keyeteach.valuedans les ressources - ✅ Convertir une liste en set avec
toset()pourfor_each
Durée estimée : 25 minutes
Difficulté : ⭐⭐⭐⭐☆ (Avancé)
Prérequis : Terraform installé, exercice 01 terminé
📖 Contexte
Répéter un bloc resource pour chaque instance est un anti-pattern en Terraform. count crée N copies indexées par un entier, tandis que for_each crée une instance par clé d'une map ou d'un set - avec des identifiants stables. Ce dernier est préférable car supprimer un élément au milieu d'une liste avec count décale les indexes et cause des recréations inattendues.
📋 Énoncé
Vous allez créer plusieurs conteneurs Docker en utilisant d'abord count, puis for_each, et observer pourquoi for_each est plus robuste lors des modifications.
Résultat attendu :
- Compréhension pratique de
countvsfor_each - Création de 3 conteneurs avec
for_each
🧭 Déroulement de l'exercice
Tâche 1 : Créer des conteneurs avec count
Créez 3 conteneurs nginx avec count = 3. Utilisez count.index pour différencier les noms et les ports.
Indice :
name = "nginx-${count.index}"etexternal = 8080 + count.index
Vérification : terraform state list affiche docker_container.web[0], [1], [2].
Tâche 2 : Observer le problème de count avec les listes
Supprimez l'élément du milieu de la liste ["web", "api", "db"] (retirer "api") et observez le plan.
Indice : Terraform veut modifier
[1](qui devient "db") et supprimer[2]. Le conteneur "db" va être recrée inutilement.
Vérification : terraform plan propose des modifications inattendues sur les ressources restantes.
Tâche 3 : Créer des conteneurs avec for_each sur une map
Utilisez for_each sur une map(object(...)) pour créer les mêmes conteneurs avec des identifiants stables.
Indice :
for_each = var.containersoùcontainersest unemap(object({ image = string, port = number })).
Vérification : terraform state list affiche docker_container.web["nginx"], ["api"], ["db"].
Tâche 4 : Supprimer un élément de for_each
Retirez "api" de la map et observez le plan : seul le conteneur "api" est supprimé, les autres sont intacts.
Indice : Avec
for_each, chaque ressource est identifiée par sa clé, pas par son index.
Vérification : terraform plan affiche uniquement - docker_container.web["api"]. Aucune modification sur "nginx" et "db".
Tâche 5 : Utiliser toset() pour une liste simple
Créez des conteneurs à partir d'une list(string) en la convertissant en set avec toset().
Indice :
for_each = toset(var.container_names)oùcontainer_names = ["web", "api"].
Vérification : each.key == each.value dans ce cas (le nom est la valeur du set).
🗂️ Mini-Projet : Infrastructure multi-services avec for_each
# variables.tf
variable "services" {
type = map(object({
image = string
port = number
}))
default = {
"frontend" = { image = "nginx:1.25", port = 8080 }
"backend" = { image = "httpd:2.4", port = 8081 }
"cache" = { image = "redis:7", port = 6379 }
}
}# main.tf
resource "docker_image" "service" {
for_each = var.services
name = each.value.image
keep_locally = false
}
resource "docker_container" "service" {
for_each = var.services
name = "svc-${each.key}"
image = docker_image.service[each.key].image_id
ports {
internal = each.key == "cache" ? 6379 : 80
external = each.value.port
}
}Checkpoints :
terraform planavecfor_eachcrée 3 images et 3 conteneursterraform state listaffiche les ressources avec leur clé (["frontend"], etc.)- Supprimer
"backend"devar.services→ seuldocker_container.service["backend"]est supprimé countavec une liste de 3 éléments : retirer l'élément 1 cause des modifications sur les éléments 1 et 2for_each = toset(["a", "b", "c"])→each.key == each.value