Создание небольшого переиспользуемого модуля

AWSBeginner
Практиковаться сейчас

Введение

Двум командам нужна одинаковая небольшая структура хранилища отчётов с разными именами, владельцами и текстом отчётов. Завершите интерфейс предоставленного модуля, вызовите его из двух независимых корневых конфигураций и расширьте коллекцию отчётов со стабильными ключами, не заменяя существующие элементы.

Вы должны понимать локальные модули, переменные, выходные значения и адреса ресурсов. Каркас ресурсов и входные значения вызывающих конфигураций уже предоставлены; вы определите их контракт и выполните развёртывание в этой новой среде с подготовленными инструментами и без личной учётной записи 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 со стабильным ключом без замены исходных отчётов. Коллекция ресурсов отличается от границы состояния среды.