Введение
Двум командам нужна одинаковая небольшая структура хранилища отчётов с разными именами, владельцами и текстом отчётов. Завершите интерфейс предоставленного модуля, вызовите его из двух независимых корневых конфигураций и расширьте коллекцию отчётов со стабильными ключами, не заменяя существующие элементы.
Вы должны понимать локальные модули, переменные, выходные значения и адреса ресурсов. Каркас ресурсов и входные значения вызывающих конфигураций уже предоставлены; вы определите их контракт и выполните развёртывание в этой новой среде с подготовленными инструментами и без личной учётной записи AWS.
Связь с сертификацией
| Сертификация | Задача экзамена | Практика |
|---|---|---|
| CloudOps Engineer – Associate (SOA-C03) | Задача 3.1, навык 3.1.6 | Базовая практика Terraform: обслуживание инфраструктуры через проверенные изменения конфигурации и состояния с сохранением рабочих ресурсов. |
Обзор лабораторной работы

Определение типизированного интерфейса модуля
На этом шаге завершите контракт входных и выходных данных небольшого переиспользуемого модуля хранилища. Дочерний модуль объединяет ресурсы за интерфейсом; корневой модуль передаёт конкретные входные значения и владеет собственным состоянием.
cd /home/labex/project/reusable-reports
cat modules/report-store/main.tf
cat dev/main.tf
Предоставленный каркас ресурсов использует var.bucket_name, var.owner и var.reports. for_each создаёт по одному экземпляру объекта на каждый ключ map, используя адреса вроде aws_s3_object.reports["daily"]. Стабильные именованные ключи отделяют существующий объект от нового добавляемого элемента. Ресурс управления версиями бакета задан как явная зависимость, чтобы при записи отчётам назначались идентификаторы версий.
Определите интерфейс. map(object({ body = string })) принимает именованную коллекцию, каждый элемент которой должен предоставлять текст отчёта. Это явно задаёт ожидания модуля вместо зависимости от недокументированной структуры входных данных:
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
Выходные значения предоставляют полезные сведения о ресурсах, не требуя от вызывающей конфигурации обращения к внутренним ресурсам модуля. Выражение for ниже строит map, сопоставляющий ключи коллекции с ключами объектов:
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
Инициализируйте корневую конфигурацию dev и проверьте контракт:
terraform -chdir=dev init
terraform -chdir=dev validate
terraform -chdir=dev plan
Ожидайте корректную конфигурацию и 3 to add: бакет, конфигурацию управления версиями и объект ежедневного отчёта. Не применяйте план, пока не проверите имя бакета, владельца и текст отчёта в вызывающей конфигурации. Независимое финансовое эталонное хранилище не связано с этим модулем и должно остаться без изменений.
Вызов одного модуля из двух независимых корневых конфигураций
На этом шаге разверните dev и preview через один и тот же модуль с разными входными значениями. Корневые конфигурации совместно используют исходные файлы модуля, а не состояние. Их отдельные рабочие каталоги сейчас используют отдельные локальные состояния; for_each разделяет только ресурсы внутри одного состояния.
Изучите и примените сохранённый план dev:
terraform -chdir=dev plan -out=dev.tfplan
Ожидайте 3 to add, 0 to change, 0 to destroy.
terraform -chdir=dev apply dev.tfplan
Прочитайте вызывающую конфигурацию preview перед её инициализацией:
cat preview/main.tf
terraform -chdir=preview init
terraform -chdir=preview validate
terraform -chdir=preview plan -out=preview.tfplan
Её отличающиеся входные значения задают module-preview-reports, владельца preview и preview daily report. Ожидайте ещё один план создания трёх ресурсов без изменений dev.
terraform -chdir=preview apply preview.tfplan
Изучите выходные значения и стабильный адрес экземпляра в каждой корневой конфигурации:
terraform -chdir=dev output
terraform -chdir=preview output
terraform -chdir=dev state list
terraform -chdir=preview state list
Обе корневые конфигурации предоставляют bucket_id и object_keys; в каждой есть экземпляр отчёта с ключом "daily", но эти адреса принадлежат разным локальным состояниям и разным бакетам. Прочитайте фактическое содержимое:
aws s3 \
cp s3://module-dev-reports/reports/daily.txt -
aws s3 \
cp s3://module-preview-reports/reports/daily.txt -
Ожидайте dev daily report и preview daily report. AWS View показывает два независимых хранилища и финансовое эталонное хранилище. Выведите текущий VersionId ежедневного отчёта dev, чтобы сравнить его после расширения коллекции:
aws s3api \
head-object \
--bucket module-dev-reports \
--key reports/daily.txt \
--query VersionId \
--output text
Добавление элемента со стабильным ключом без замены существующих отчётов
На этом шаге расширьте только map среды dev. Изменение ключей коллекции меняет идентичность экземпляров ресурсов; сохранение ключа daily и добавление weekly должны оставить ежедневный объект нетронутым.
Замените вызывающую конфигурацию dev, сохранив существующие входные значения и добавив один новый элемент:
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
Изучите изменение:
terraform -chdir=dev plan -out=extra.tfplan
Ожидайте 1 to add, 0 to change, 0 to destroy с добавлением только module.report_store.aws_s3_object.reports["weekly"]. Если существующий ежедневный объект или бакет заменяется, остановитесь и сравните ключи и входные значения, которые должны оставаться неизменными.
terraform -chdir=dev apply extra.tfplan
Сравните VersionId ежедневного отчёта с выводом предыдущего шага:
aws s3api \
head-object \
--bucket module-dev-reports \
--key reports/daily.txt \
--query VersionId \
--output text
Это должна быть та же исходная версия. Прочитайте новый элемент и независимый отчёт preview:
aws s3 \
cp s3://module-dev-reports/reports/weekly.txt -
aws s3 \
cp s3://module-preview-reports/reports/daily.txt -
Ожидайте dev weekly report и неизменённый preview daily report. Фоновая проверка сравнивает версии, созданные сервисом при первоначальной записи, а не принимает одинаковые байты в заменённых объектах как достаточное подтверждение.
terraform -chdir=dev output
terraform -chdir=dev plan
terraform -chdir=preview plan
Выходной map dev содержит оба ключа; у preview по-прежнему только daily. Для обеих корневых конфигураций план должен подтвердить согласованность сообщением No changes. Оставьте рабочие хранилища доступными. Этот модуль определяет интерфейс и коллекцию ресурсов; выбор отдельных ключей удалённого backend — дополнительное решение об изоляции сред, которое рассматривается позже.
Об использовании входных и выходных данных модуля в качестве границ читайте в руководстве HashiCorp по композиции модулей.
Резюме
Вы написали типизированный интерфейс модуля, вернули полезные выходные значения в две независимые корневые конфигурации и добавили элемент for_each со стабильным ключом без замены исходных отчётов. Коллекция ресурсов отличается от границы состояния среды.



