Справочник - TF-PRO HashiCorp Terraform Authoring and Operations Professional
Последняя проверка: май 2026 г.
Сжатый справочник архитектурных шаблонов, проверяемых на экзамене TF-PRO. Читайте сверху вниз или переходите к нужному разделу.
HCL и конфигурация
Ресурсу требуется переменное количество идентичных вложенных блоков (например, правил входящего трафика), определяемое списком/картой.
Используйте динамический блок, чей `for_each` перебирает коллекцию; ссылайтесь на каждый элемент через итератор блока (имя по умолчанию = метка блока) внутри `content {}`.
Почему: Динамические блоки генерируют повторяющиеся вложенные блоки без копирования и вставки; итератор привязывает каждый сгенерированный блок к его исходному элементу.
Создайте один ресурс на каждую запись в карте объектов, со стабильным ключом, чтобы изменение порядка никогда не приводило к замене.
Установите `for_each = var.objects` (карту). Используйте `each.key` для стабильного ключа и `each.value.<attr>` для полей. Избегайте `count` здесь - смещения индексов вызывают пересоздание.
Почему: Ключи карты являются стабильными идентификаторами в состоянии; индексы списка позиционны и смещаются при добавлении/удалении элементов.
Выберите между `count` и `for_each` для нескольких экземпляров.
Используйте `for_each`, когда экземпляры имеют различные идентификаторы (набор/карта); используйте `count` только для N идентичных, нечувствительных к порядку копий. Предпочтите `for_each` для всего, что может увеличиваться/уменьшаться.
Почему: `for_each` обращается по ключу (resource["key"]); `count` обращается по индексу (resource[0]), который перетасовывается при вставках/удалениях.
Входная переменная является объектом, где некоторые атрибуты необязательны и требуют значений по умолчанию.
Укажите тип как `object({ name = string, size = optional(number, 10) })`. `optional(type, default)` предоставляет значение по умолчанию, когда вызывающий объект опускает атрибут.
Почему: `optional()` со значением по умолчанию делает вызовы лаконичными, гарантируя конкретное значение далее по цепочке - без обработки `null` повсюду.
Проверить предположение о ресурсе перед применением или гарантировать результат после.
Используйте `lifecycle { precondition { ... } }` для проверки входных данных перед созданием/обновлением и `postcondition` для проверки выходных данных после. Оба принимают `condition` + `error_message`.
Почему: Пользовательские условия быстро выдают ошибку с четким сообщением, вместо того чтобы приводить к сбою применения или запутанной ошибке далее по цепочке.
Ресурс должен быть пересоздан всякий раз, когда изменяется другой ресурс или атрибут.
Добавьте `lifecycle { replace_triggered_by = [aws_x.y.id] }`. Когда ссылочное значение изменяется, Terraform принудительно заменяет этот ресурс.
Почему: Декларативно выражает зависимость замены, избегая ручного `-replace` при каждом связанном изменении.
Замена ресурса вызывает простой, потому что старый уничтожается до того, как появится новый.
Установите `lifecycle { create_before_destroy = true }`, чтобы Terraform сначала создал замену, а затем уничтожил старый. Обеспечьте уникальные имена/отсутствие жестких конфликтов.
Почему: Замена без простоя; но следите за конфликтами имен и ограничениями квот, пока оба существуют в течение короткого времени.
Отклонять недопустимые входные значения на ранней стадии (например, окружение, которое не является dev/stage/prod).
Добавьте блок `validation { condition = contains(["dev","stage","prod"], var.env), error_message = "..." }` к переменной.
Почему: Перехватывает некорректный ввод на этапе планирования с читаемым сообщением, вместо сбоя глубоко внутри вызова провайдера.
Ссылаться на значение, которое может не существовать, без сбоя плана.
Используйте `try(local.maybe.value, "default")` для отката при ошибках или `can(expr)` для получения логического значения, указывающего, успешно ли выражение.
Почему: Избегает "Error: Unsupported attribute" при отсутствии ключей; обеспечивает корректную обработку опциональных/переменных данных.
Преобразовать список в карту или отфильтровать/изменить форму коллекции для аргумента ресурса.
Используйте выражение `for`: `{ for u in var.users : u.name => u.role if u.active }` (карта) или `[for x in list : upper(x)]` (список).
Почему: Выражения `for` - идиоматический способ изменения формы данных; предложение `if` фильтрует, форма `k => v` создает карты.
Переменная или вывод содержат секрет, который не должен отображаться в выводе плана/применения.
Пометьте переменную `sensitive = true` (и выводы тоже). Terraform скрывает ее в выводе CLI, хотя она все еще хранится в состоянии.
Почему: Предотвращает случайное раскрытие в логах/выводе CI; само состояние все еще должно быть защищено (зашифрованный бэкенд, контроль доступа).
Управлять ресурсами в двух регионах/аккаунтах в рамках одной конфигурации.
Объявите псевдонимы провайдеров (`provider "aws" { alias = "west" region = "us-west-2" }`) и установите `provider = aws.west` для ресурсов или передайте их в модули.
Почему: Псевдонимы позволяют одной конфигурации использовать несколько экземпляров провайдеров; модули получают их явно через аргумент `providers`.
Скрытая зависимость (не выраженная через ссылки) вызывает проблемы с порядком.
Добавьте `depends_on = [aws_iam_role_policy.x]`, чтобы принудительно установить порядок. Используйте экономно - предпочитайте неявные зависимости через ссылки на атрибуты.
Почему: Явный `depends_on` обрабатывает зависимости, которые граф не может вывести, но чрезмерное использование создает консервативные, более медленные планы.
Рендеринг файла конфигурации/пользовательских данных из шаблона со структурированными переменными.
Используйте `templatefile("${path.module}/tpl.tftpl", { items = local.items })`; шаблон использует интерполяцию `%{ for }` / `${}`.
Почему: `templatefile` обеспечивает чистый рендеринг на этапе планирования (в отличие от устаревшего провайдера `template`) и поддерживает циклы/условные выражения.
Создайте плоский список каждой комбинации (подсеть, правило) для подачи в один `for_each`.
Используйте `setproduct(var.subnets, var.rules)` для декартова произведения или `flatten([for ...])` для схлопывания вложенных списков в один.
Почему: Эти функции преобразуют вложенные данные в плоскую, уникально-ключевую коллекцию, которую требует `for_each`.
Модули
Модуль реестра изменяется и неожиданно модифицирует инфраструктуру при следующей инициализации.
Закрепите версию с `version = "~> 4.2"` (только для модулей реестра). Для источников Git закрепите тег `?ref=v4.2.0`. Запустите `terraform init -upgrade` намеренно, чтобы обновить закрепленные версии.
Почему: Незакрепленные модули обновляются до последней версии; закрепление делает обновления преднамеренными и подлежащими проверке.
Корневому модулю требуется значение, произведенное глубоко внутри дочернего модуля.
Выведите его как `output` в дочернем модуле, затем ссылайтесь на `module.child.output_name`. Значения, которые не являются выходными, недоступны вызывающим объектам.
Почему: Модули инкапсулированы; выводы - единственный способ передачи данных через границу модуля вверх.
Создать экземпляр одного и того же модуля один раз для каждой команды/окружения из карты.
Установите `for_each` в блоке модуля: `module "env" { for_each = var.envs; source = "./env"; name = each.key }`. Ссылайтесь на `module.env["prod"]`.
Почему: `for_each` для модулей масштабирует шаблон без копирования и вставки блоков; ключи дают стабильные адреса.
Дочерний модуль должен создавать ресурсы в нестандартном (псевдонимном) провайдере.
Передавайте провайдеры явно: `module "x" { providers = { aws = aws.west } }`. Дочерний модуль объявляет провайдер в `required_providers` с `configuration_aliases`.
Почему: Модули не наследуют псевдонимные провайдеры неявно; карта провайдеров связывает родительский псевдоним с дочерним.
Переименование ресурса или его перемещение в модуль обычно приводит к его уничтожению и пересозданию.
Добавьте блок `moved { from = aws_instance.old; to = module.compute.aws_instance.new }`. Terraform обновляет адреса состояния без уничтожения.
Почему: Блоки `moved` делают рефакторинг безопасным и проверяемым в коде, заменяя ручной `terraform state mv`.
Монолитный модуль стал громоздким и смешивает сетевые, вычислительные и данные проблемы.
Разделите на сфокусированные дочерние модули и соберите их в корневом, передавая выводы одного в качестве входов следующему. Сохраняйте модули одноцелевыми.
Почему: Композиция улучшает повторное использование и тестируемость; модули с ограниченной областью действия версионируются и развиваются независимо.
Потребители передают недопустимые комбинации входных данных в общий модуль.
Добавьте блоки `validation` и `precondition` внутри модуля для обеспечения контрактов и документируйте входы с помощью `description`.
Почему: Модуль владеет своим контрактом; внутренняя проверка защищает каждого вызывающего, а не только одну корневую конфигурацию.
Глубоко вложенные модули затрудняют отслеживание потока данных и передачу провайдеров.
Сохраняйте вложенность мелкой (1-2 уровня). Явно передавайте провайдеров и ключевые входные данные на каждом уровне; избегайте опоры на глубокое неявное наследование.
Почему: Неглубокие деревья легче анализировать; глубокая вложенность увеличивает сложность передачи провайдеров и подключения выводов.
Опубликовать переиспользуемый модуль в приватном реестре и развивать его, не нарушая работу вызывающих объектов.
Помечайте релизы семантическим версионированием (`v1.2.0`); критические изменения входных/выходных данных увеличивают основную версию. Вызывающие объекты закрепляют версии с ограничениями `~>`.
Почему: Семантическое версионирование позволяет потребителям безопасно внедрять исправления/функции и сознательно переходить на критические изменения.
Выберите, откуда получать модуль для заданного уровня зрелости.
Локальные пути (`./modules/x`) для внутрирепозиторных, Git (`git::...?ref=tag`) для общих, но неопубликованных, реестр (`namespace/name/provider`) для версионированных/опубликованных модулей.
Почему: Тип источника соответствует области совместного использования; только источники реестра поддерживают аргумент `version` и разрешение ограничений.
Вывод модуля содержит секрет, используемый корневым модулем.
Пометьте вывод модуля `sensitive = true`. Использование его в нечувствительном контексте вызовет ошибку, пока вы также не обработаете его как чувствительный.
Почему: Чувствительность распространяется через границу модуля, предотвращая случайную утечку в корневом выводе.
Существующий набор ресурсов, основанный на `count`, должен стать `for_each` без уничтожения экземпляров.
Добавьте блоки `moved`, сопоставляющие каждый индекс `resource[0]` новому адресу `resource["key"]`, затем переключитесь на `for_each`.
Почему: Блоки `moved` переназначают ключи состояния с позиционного на адресное, избегая уничтожения/пересоздания.
Управление CLI и состоянием
Вы переименовали ресурс в конфигурации; план теперь хочет уничтожить старый и создать новый.
Предпочтите блок `moved` в конфигурации. Для специальных/CLI исправлений используйте `terraform state mv aws_x.old aws_x.new`, чтобы перенаправить существующий объект.
Почему: Оба обновляют адрес состояния, поэтому Terraform видит существующий объект как переименованный ресурс - без уничтожения.
Перевести существующий, созданный вручную ресурс под управление Terraform.
Добавьте блок `import { to = aws_x.y; id = "i-123" }` и запустите `terraform plan -generate-config-out=gen.tf` для создания шаблона конфигурации, затем доработайте и примените.
Почему: Импорт, управляемый конфигурацией, подлежит проверке и генерирует начальную конфигурацию, в отличие от более старого императивного `terraform import`.
Прекратить управление ресурсом с помощью Terraform, но оставить его работающим в облаке.
Запустите `terraform state rm aws_x.y`. Terraform забывает объект; он не уничтожается. Также удалите его конфигурацию, чтобы избежать плана пересоздания.
Почему: `state rm` отсоединяет без удаления - полезно при передаче ресурса другому инструменту/команде.
Переместить состояние из локального бэкенда в S3 (или в HCP Terraform).
Добавьте/замените блок `backend`/`cloud`, запустите `terraform init` - Terraform обнаружит изменение и предложит мигрировать существующее состояние в новый бэкенд.
Почему: `init` организует копирование; ответ "да" безопасно мигрирует состояние, а не начинает с нуля.
Два инженера одновременно запускают `apply` для одного и того же удаленного состояния.
Используйте бэкенд, который поддерживает блокировку (S3+DynamoDB, HCP Terraform и т.д.). Terraform приобретает блокировку для каждой операции; второй запуск ждет или выдает ошибку.
Почему: Блокировка предотвращает одновременные записи, которые могли бы повредить состояние. Никогда не отключайте ее бездумно.
Сбойное применение оставило устаревшую блокировку, и теперь каждый запуск заблокирован.
Убедитесь, что никакая операция фактически не выполняется, затем выполните `terraform force-unlock <LOCK_ID>`. Используйте ID из сообщения об ошибке.
Почему: `force-unlock` снимает "осиротевшую" блокировку; выполнение этого во время реальной операции рискует повреждением состояния.
Обнаружить расхождение между конфигурацией/состоянием и реальной инфраструктурой, не предлагая изменений.
Запустите `terraform plan -refresh-only` (или `apply -refresh-only` для обновления состояния). Он сообщает о различиях без планирования изменений ресурсов.
Почему: Отделяет обнаружение дрейфа от планирования изменений - вы видите, что изменилось в облаке, прежде чем решить, как это исправить.
Ресурс работает некорректно, и вы хотите пересоздать его без редактирования конфигурации.
Запустите `terraform apply -replace="aws_instance.web"`. Это современная замена устаревшего `terraform taint`.
Почему: -replace принудительно уничтожает и пересоздает один ресурс при следующем применении, декларативно через CLI.
Вы испытываете искушение регулярно использовать `-target` для ускорения применений.
Используйте `-target` только для восстановления после ошибок или точечных исправлений. Избегайте его в качестве обычного рабочего процесса - он приводит к частичным применениям и может пропускать зависимости.
Почему: Регулярное использование `-target` скрывает проблемы зависимостей и приводит к неполному состоянию; HashiCorp описывает его как исключительный инструмент.
Провайдер изменил пространство имен (например, hashicorp/aws на форк), и состояние ссылается на старый адрес.
Запустите `terraform state replace-provider registry.terraform.io/hashicorp/aws registry.example.com/org/aws`.
Почему: Перезаписывает ссылки на провайдеры в состоянии, чтобы `init`/`plan` разрешали новый источник без пересоздания ресурсов.
Одна конфигурация нуждается в выводах, произведенных другой конфигурацией/рабочей областью.
Используйте источник данных `terraform_remote_state` (или выводы запуска HCP Terraform) для чтения выводов другого состояния в режиме только для чтения.
Почему: Совместное использование значений между границами состояния без дублирования ресурсов; доступны только экспортированные выводы.
Настройки бэкенда (корзина, ключ) различаются для разных окружений и не должны быть жестко закодированы.
Оставьте их вне блока `backend` и передайте при `init`: `terraform init -backend-config=prod.hcl` (или `-backend-config="key=..."`).
Почему: Частичная конфигурация делает одну конфигурацию многократно используемой в разных окружениях, предоставляя значения бэкенда, специфичные для окружения, при инициализации.
Вам нужно отдельное состояние для dev/stage/prod из одной конфигурации.
Используйте рабочие области CLI (`terraform workspace new prod`) для легкой изоляции или отдельные корневые конфигурации/рабочие области HCP для более сильного разделения.
Почему: Каждая рабочая область имеет собственное состояние; ссылайтесь на `terraform.workspace` для изменения именования/размера. Для сильной изоляции предпочитайте отдельные бэкенды/рабочие области.
Операции HCP Terraform
Избегайте хранения долгосрочных облачных ключей в переменных рабочей области HCP Terraform.
Настройте динамические учетные данные провайдера: HCP Terraform использует OIDC/идентификацию рабочей нагрузки для получения краткосрочных учетных данных от AWS/Azure/GCP/Vault для каждого запуска.
Почему: Устраняет статические секреты; учетные данные создаются "точно в срок" и истекают, уменьшая зону поражения.
Одни и те же переменные (конфигурация провайдера, теги) требуются во многих рабочих областях.
Определите набор переменных и примените его к проекту или выбранным рабочим областям. Переменные уровня рабочей области переопределяют значения набора переменных.
Почему: Наборы переменных избегают дублирования общей конфигурации; приоритет (рабочая область > набор) позволяет рабочей области переопределять значения при необходимости.
Обеспечить защитные меры (нет публичного S3, обязательные теги) при каждом запуске.
Присоедините набор политик Sentinel или OPA. Установите уровень принуждения: рекомендательный (предупреждение), мягко-обязательный (переопределение с разрешением) или жестко-обязательный (блокировка).
Почему: Политика как код централизованно управляет запусками; уровни принуждения балансируют строгость с операционной гибкостью.
Интегрировать внешнюю проверку (оценка стоимости, сканирование безопасности) в конвейер запуска.
Настройте задачу выполнения на определенном этапе (до плана, после плана, до применения). HCP Terraform вызывает внешний сервис и управляет запуском на основе его результата.
Почему: Задачи выполнения расширяют конвейер сторонними проверками без пользовательской настройки CI.
Выберите, как запускаются выполнения для рабочей области.
Управляемые VCS (коммит/PR запускает план), управляемые CLI (`terraform plan/apply` для удаленного репозитория) или управляемые API (загруженная конфигурация). Выбирайте в соответствии с рабочим процессом команды.
Почему: Управляемые VCS подходят для GitOps; управляемые CLI подходят для локальной итерации; управляемые API подходят для пользовательских конвейеров. Они взаимоисключающи для каждой рабочей области.
Предоставить команде доступ на запись к промежуточным рабочим областям, но только на чтение к производственным.
Определите область разрешений на уровне организации/проекта/рабочей области: назначьте доступ команды (чтение/планирование/запись/администрирование) для каждого проекта или рабочей области; используйте группировку проектов для управления в масштабе.
Почему: Детальные, ограниченные разрешения обеспечивают принцип наименьших привилегий; гранты на уровне проекта сокращают управление по каждой рабочей области.
Применение рабочей области сети должно автоматически ставить в очередь запуск в зависимых рабочих областях приложений.
Настройте триггер запуска: нижестоящая рабочая область подписывается на вышестоящую; успешное применение ставит в очередь запуск нижестоящей рабочей области.
Почему: Триггеры запуска связывают зависимые рабочие области, чтобы изменения общей инфраструктуры распространялись по порядку.
Позволить пользователям, не использующим Terraform, развертывать стандартизированную инфраструктуру с помощью формы.
Опубликуйте модуль без кода в приватном реестре; пользователи создают его через UI, предоставляя только входные данные - без написания HCL.
Почему: Модули без кода демократизируют самообслуживание, сохраняя при этом управляемость и версионирование базовой конфигурации.
Совместно использовать проверенные модули и провайдеры в рамках организации.
Опубликуйте в приватном реестре HCP Terraform; потребители ссылаются на `app.terraform.io/org/name/provider` с ограничениями по версии.
Почему: Приватный реестр централизует обнаружение, версионирование и управление внутренними модулями.
Организовать десятки рабочих областей по командам/приложениям для разрешений и наборов переменных.
Группируйте рабочие области в проекты; применяйте разрешения команд и наборы переменных на уровне проекта.
Почему: Проекты масштабируют управление - вы управляете доступом и общей конфигурацией на уровне проекта, а не на уровне каждой рабочей области.
Постоянно обнаруживать, когда производственная среда отклоняется от настроенного состояния.
Включите оценки работоспособности (обнаружение дрейфа / непрерывная проверка) в рабочей области; HCP Terraform периодически обновляет и сообщает о дрейфе и неудачных утверждениях.
Почему: Автоматические оценки выявляют дрейф и нарушенные постусловия между применениями, прежде чем они приведут к инцидентам.
HCP Terraform должен достигать инфраструктуры внутри частной сети без публичного входящего трафика.
Разверните агенты HCP Terraform в частной сети и назначьте рабочую область пулу агентов; запуски выполняются через агент.
Почему: Агенты позволяют HCP Terraform работать с частными/изолированными средами, не делая их общедоступными.
Неудачное применение повредило состояние, и вам нужно восстановиться.
HCP Terraform хранит версионированное состояние; выполните откат к предыдущей версии состояния из UI/API рабочей области и перепланируйте.
Почему: Встроенное версионирование состояния предоставляет точки восстановления без необходимости самостоятельно управлять снимками бэкенда.