Introducción
Dos equipos necesitan el mismo diseño de un pequeño almacén de informes, con nombres, propietarios y textos de informe diferentes. Completa la interfaz de un módulo suministrado, invócalo desde dos configuraciones raíz independientes y amplía una colección estable de informes sin sustituir los miembros existentes.
Debes conocer los módulos locales, las variables, los valores de salida y las direcciones de recursos. Se proporcionan la estructura básica de los recursos y las entradas de las configuraciones que invocan el módulo; definirás su contrato y los desplegarás en este entorno nuevo, con las herramientas preparadas y sin una cuenta personal de AWS.
Relación con las certificaciones
| Certificación | Tarea del examen | Práctica |
|---|---|---|
| CloudOps Engineer – Associate (SOA-C03) | Tarea 3.1, habilidad 3.1.6 | Práctica básica de Terraform: mantener infraestructura mediante cambios revisados en la configuración y el estado, conservando los recursos en funcionamiento. |
Vista general del laboratorio

Define una interfaz de módulo con tipos explícitos
En este paso, completa el contrato de entradas y salidas de un pequeño módulo de almacenamiento reutilizable. Un módulo hijo agrupa recursos detrás de una interfaz; un módulo raíz proporciona entradas concretas y tiene su propio estado.
cd /home/labex/project/reusable-reports
cat modules/report-store/main.tf
cat dev/main.tf
La estructura básica de recursos suministrada usa var.bucket_name, var.owner y var.reports. for_each crea una instancia de objeto por cada clave del mapa, con direcciones como aws_s3_object.reports["daily"]. Las claves estables con nombre mantienen un objeto existente separado de un miembro recién añadido. El recurso de control de versiones del bucket es una dependencia explícita para que las escrituras de informes reciban identidades de versión.
Define la interfaz. map(object({ body = string })) acepta una colección con nombres cuyos miembros deben proporcionar, cada uno, el texto de un informe. Esto hace explícito lo que espera el módulo, en lugar de depender de estructuras de entrada sin documentar:
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
Los valores de salida exponen información útil de los recursos sin exigir que la configuración que invoca el módulo acceda a su interior. La expresión for siguiente construye un mapa que asocia cada clave con la clave de su objeto:
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
Inicializa la configuración raíz de desarrollo y comprueba el contrato:
terraform -chdir=dev init
terraform -chdir=dev validate
terraform -chdir=dev plan
Debes obtener una configuración válida y 3 to add: su bucket, la configuración de control de versiones y el objeto del informe diario. No apliques los cambios hasta haber comprobado el nombre del bucket, el propietario y el texto del informe en la configuración que invoca el módulo. La referencia de finanzas independiente es ajena a este módulo y debe permanecer sin cambios.
Invoca el mismo módulo desde dos configuraciones raíz independientes
En este paso, despliega desarrollo y vista previa mediante el mismo módulo con entradas diferentes. Las configuraciones raíz comparten los archivos fuente del módulo, pero no el estado. Sus directorios de trabajo separados utilizan actualmente estados locales independientes; for_each solo separa recursos dentro de un mismo estado.
Revisa y aplica el plan guardado de desarrollo:
terraform -chdir=dev plan -out=dev.tfplan
Debes ver 3 to add, 0 to change, 0 to destroy.
terraform -chdir=dev apply dev.tfplan
Lee la configuración que invoca el módulo para vista previa antes de inicializarla:
cat preview/main.tf
terraform -chdir=preview init
terraform -chdir=preview validate
terraform -chdir=preview plan -out=preview.tfplan
Sus entradas diferentes seleccionan module-preview-reports, el propietario preview y preview daily report. Debes obtener otro plan de creación de tres recursos, sin cambios en desarrollo.
terraform -chdir=preview apply preview.tfplan
Inspecciona los valores de salida y la dirección estable de la instancia en cada configuración raíz:
terraform -chdir=dev output
terraform -chdir=preview output
terraform -chdir=dev state list
terraform -chdir=preview state list
Ambas configuraciones raíz exponen bucket_id y object_keys; cada una tiene una instancia de informe con la clave "daily", pero esas direcciones pertenecen a estados locales y buckets diferentes. Lee el contenido real:
aws s3 \
cp s3://module-dev-reports/reports/daily.txt -
aws s3 \
cp s3://module-preview-reports/reports/daily.txt -
Debes ver dev daily report y preview daily report. AWS View muestra dos almacenes independientes y la referencia de finanzas. Muestra el VersionId actual del informe diario de desarrollo para poder compararlo después de ampliar la colección:
aws s3api \
head-object \
--bucket module-dev-reports \
--key reports/daily.txt \
--query VersionId \
--output text
Añade un miembro estable a la colección sin sustituir los informes existentes
En este paso, amplía únicamente el mapa de desarrollo. Cambiar las claves de una colección cambia la identidad de las instancias de recursos; conservar la clave daily y añadir weekly debe dejar intacto el objeto diario.
Sustituye la configuración que invoca el módulo para desarrollo por las mismas entradas existentes y un miembro nuevo:
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
Revisa el cambio:
terraform -chdir=dev plan -out=extra.tfplan
Debes ver 1 to add, 0 to change, 0 to destroy, añadiendo únicamente module.report_store.aws_s3_object.reports["weekly"]. Si se sustituye el objeto diario existente o el bucket, detente y compara las claves y las entradas que deben permanecer sin cambios.
terraform -chdir=dev apply extra.tfplan
Compara el VersionId del informe diario con la salida del paso anterior:
aws s3api \
head-object \
--bucket module-dev-reports \
--key reports/daily.txt \
--query VersionId \
--output text
Debe ser la misma versión original. Lee el miembro nuevo y el informe independiente de vista previa:
aws s3 \
cp s3://module-dev-reports/reports/weekly.txt -
aws s3 \
cp s3://module-preview-reports/reports/daily.txt -
Debes ver dev weekly report y el texto sin cambios preview daily report. La comprobación en segundo plano compara las versiones nativas de la primera escritura, en lugar de aceptar objetos sustituidos que tengan bytes idénticos.
terraform -chdir=dev output
terraform -chdir=dev plan
terraform -chdir=preview plan
El mapa de salida de desarrollo contiene ambas claves; vista previa sigue teniendo solo el informe diario. Ambas configuraciones raíz deben converger con No changes. Mantén disponibles los almacenes en funcionamiento. Este módulo define una interfaz y una colección de recursos; elegir claves independientes en un backend remoto es una decisión adicional de aislamiento de entornos que se tratará más adelante.
Consulta las orientaciones sobre composición de módulos de HashiCorp para usar las entradas y salidas de los módulos como límites.
Resumen
Has definido una interfaz de módulo con tipos explícitos, devuelto valores de salida útiles a dos configuraciones raíz independientes y añadido un miembro estable de for_each sin sustituir los informes originales. Una colección de recursos es distinta del límite que establece el estado de un entorno.



