Introduction
Deux équipes ont besoin du même petit modèle de stockage de rapports, avec des noms, des propriétaires et des textes de rapport différents. Complétez l'interface d'un module fourni, appelez-le depuis deux configurations racines indépendantes et étendez une collection stable de rapports sans remplacer les éléments existants.
Vous devez connaître les modules locaux, les variables, les sorties et les adresses de ressources. Le squelette des ressources et les entrées des appelants sont fournis ; vous définissez leur contrat et les déployez dans cet environnement neuf, avec des outils préparés et sans compte AWS personnel.
Liens avec les certifications
| Certification | Tâche de l'examen | Mise en pratique |
|---|---|---|
| CloudOps Engineer – Associate (SOA-C03) | Tâche 3.1, compétence 3.1.6 | Pratique des bases de Terraform : maintenir l'infrastructure par des modifications examinées de la configuration et de l'état, tout en préservant les ressources opérationnelles. |
Aperçu du lab

Définir une interface de module typée
Dans cette étape, complétez le contrat d'entrée et de sortie d'un petit module de stockage réutilisable. Un module enfant regroupe des ressources derrière une interface ; un module racine fournit des entrées concrètes et possède son propre état.
cd /home/labex/project/reusable-reports
cat modules/report-store/main.tf
cat dev/main.tf
Le squelette de ressources fourni utilise var.bucket_name, var.owner et var.reports. for_each crée une instance d'objet par clé de map, avec des adresses telles que aws_s3_object.reports["daily"]. Des clés nommées stables permettent de distinguer un objet existant d'un nouvel élément ajouté. La ressource de gestion des versions du bucket constitue une dépendance explicite afin que les écritures de rapports reçoivent des identifiants de version.
Définissez l'interface. map(object({ body = string })) accepte une collection nommée dont chaque élément doit fournir le texte d'un rapport. Ce type rend explicites les attentes du module au lieu de dépendre de structures d'entrée non documentées :
cat > modules/report-store/variables.tf <<'HCL'
variable "bucket_name" {
type = string
description = "Unique bucket name supplied by this environment root."
}
variable "owner" {
type = string
description = "Owner tag supplied by the caller."
}
variable "reports" {
type = map(object({ body = string }))
description = "Stable report keys and their text content."
}
HCL
Les sorties exposent des informations utiles sur les ressources sans obliger l'appelant à accéder à l'intérieur du module. L'expression for ci-dessous construit une map associant chaque clé à une clé d'objet :
cat > modules/report-store/outputs.tf <<'HCL'
output "bucket_id" {
value = aws_s3_bucket.store.id
}
output "object_keys" {
value = { for key, report in aws_s3_object.reports : key => report.key }
}
HCL
Initialisez la configuration racine dev et vérifiez le contrat :
terraform -chdir=dev init
terraform -chdir=dev validate
terraform -chdir=dev plan
La configuration doit être valide et le plan doit indiquer 3 to add : son bucket, sa configuration de gestion des versions et son objet de rapport quotidien. N'appliquez pas le plan avant d'avoir vérifié le nom du bucket, le propriétaire et le texte du rapport dans l'appelant. La référence indépendante de la finance est sans lien avec ce module et doit rester inchangée.
Appeler le même module depuis deux configurations racines indépendantes
Dans cette étape, déployez dev et preview via le même module avec des entrées différentes. Les configurations racines partagent les fichiers source du module, pas l'état. Leurs répertoires de travail distincts utilisent actuellement des états locaux séparés ; for_each sépare uniquement les ressources à l'intérieur d'un même état.
Examinez et appliquez le plan enregistré de dev :
terraform -chdir=dev plan -out=dev.tfplan
Le résultat attendu est 3 to add, 0 to change, 0 to destroy.
terraform -chdir=dev apply dev.tfplan
Lisez l'appelant de preview avant de l'initialiser :
cat preview/main.tf
terraform -chdir=preview init
terraform -chdir=preview validate
terraform -chdir=preview plan -out=preview.tfplan
Ses entrées distinctes sélectionnent module-preview-reports, le propriétaire preview et preview daily report. Un autre plan de création de trois ressources est attendu, sans modification de dev.
terraform -chdir=preview apply preview.tfplan
Inspectez les sorties et l'adresse d'instance stable dans chaque configuration racine :
terraform -chdir=dev output
terraform -chdir=preview output
terraform -chdir=dev state list
terraform -chdir=preview state list
Les deux configurations racines exposent bucket_id et object_keys ; chacune possède une instance de rapport dont la clé est "daily", mais ces adresses appartiennent à des états locaux et à des buckets différents. Lisez le contenu réel :
aws s3 \
cp s3://module-dev-reports/reports/daily.txt -
aws s3 \
cp s3://module-preview-reports/reports/daily.txt -
Les résultats attendus sont dev daily report et preview daily report. AWS View affiche deux stockages indépendants ainsi que la référence de la finance. Affichez le VersionId actuel du rapport quotidien de dev pour pouvoir le comparer après avoir étendu la collection :
aws s3api \
head-object \
--bucket module-dev-reports \
--key reports/daily.txt \
--query VersionId \
--output text
Ajouter un élément stable à la collection sans remplacer les rapports existants
Dans cette étape, étendez uniquement la map de dev. Modifier les clés d'une collection modifie l'identité des instances de ressources ; conserver la clé daily et ajouter weekly doit laisser l'objet quotidien intact.
Remplacez l'appelant de dev en conservant les mêmes entrées existantes et en ajoutant un nouvel élément :
cat > dev/main.tf <<'HCL'
module "report_store" {
source = "../modules/report-store"
bucket_name = "module-dev-reports"
owner = "dev"
reports = {
daily = { body = "dev daily report\n" }
weekly = { body = "dev weekly report\n" }
}
}
output "bucket_id" { value = module.report_store.bucket_id }
output "object_keys" { value = module.report_store.object_keys }
HCL
Examinez la modification :
terraform -chdir=dev plan -out=extra.tfplan
Le résultat attendu est 1 to add, 0 to change, 0 to destroy, avec l'ajout du seul élément module.report_store.aws_s3_object.reports["weekly"]. Si l'objet quotidien existant ou le bucket est remplacé, arrêtez-vous et comparez les clés et les entrées qui doivent rester inchangées.
terraform -chdir=dev apply extra.tfplan
Comparez le VersionId du rapport quotidien avec la sortie de l'étape précédente :
aws s3api \
head-object \
--bucket module-dev-reports \
--key reports/daily.txt \
--query VersionId \
--output text
Il doit s'agir de la même version d'origine. Lisez le nouvel élément et le rapport indépendant de preview :
aws s3 \
cp s3://module-dev-reports/reports/weekly.txt -
aws s3 \
cp s3://module-preview-reports/reports/daily.txt -
Les résultats attendus sont dev weekly report et le texte inchangé preview daily report. Le contrôle en arrière-plan compare les versions natives de première écriture, au lieu d'accepter des octets identiques dans des objets de remplacement.
terraform -chdir=dev output
terraform -chdir=dev plan
terraform -chdir=preview plan
La map de sortie de dev contient les deux clés ; preview ne contient toujours que daily. Les deux configurations racines doivent converger avec No changes. Gardez les stockages opérationnels disponibles. Ce module définit une interface et une collection de ressources ; choisir des clés distinctes de backend distant est une décision supplémentaire d'isolation des environnements, abordée plus tard.
Consultez les conseils de HashiCorp sur la composition des modules pour utiliser les entrées et les sorties des modules comme frontières.
Résumé
Vous avez rédigé une interface de module typée, renvoyé des sorties utiles à deux configurations racines indépendantes et ajouté un élément stable avec for_each sans remplacer les rapports d'origine. Une collection de ressources est distincte d'une frontière d'état entre environnements.



