Нативный terraform test и статический анализ

Рейтинг: 62.1% · 15 голосов
Подробный курс по Terraform и OpenTofu на примерах Yandex Cloud: ресурсы и провайдеры, состояние и бэкенды, модули, циклы и условия HCL, секреты и Lockbox, тестирование, CI/CD и командная работа. С актуализацией на 2026 (Terraform 1.3-1.10, OpenTofu).
Ответить
Аватара пользователя
Vlad_DevOps
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Нативный terraform test и статический анализ

Сообщение Vlad_DevOps »

Оглавление курса (47)
  1. Что такое инфраструктура как код и зачем она нужна
  2. Категории инструментов IaC: чем отличаются Ansible, Packer, Kubernetes и Terraform
  3. Чем Terraform отличается от Ansible, Pulumi и CloudFormation
  4. Как работает Terraform под капотом и кто такой OpenTofu
  5. Установка Terraform и OpenTofu, подготовка Yandex Cloud
  6. Первый ресурс: разворачиваем виртуальную машину в Yandex Cloud
  7. Веб-сервер на ВМ: метаданные, user-data и группы безопасности
  8. Переменные ввода и выходные значения в Terraform
  9. Кластер ВМ: группа экземпляров Yandex Compute Instance Group
  10. Балансировщик нагрузки: Application Load Balancer в Yandex Cloud
  11. Состояние Terraform: что такое tfstate и чем опасен локальный файл
  12. Удалённое хранилище состояния: бэкенд на Yandex Object Storage
  13. Изоляция состояния: рабочие области против раскладки по папкам
  14. Источники данных и terraform_remote_state: связываем компоненты
  15. Модули Terraform: переиспользуем инфраструктуру
  16. Входные, локальные и выходные переменные модуля
  17. Версионирование модулей и подводные камни
  18. Циклы в Terraform: параметр count
  19. Циклы в Terraform: for_each по множествам и картам
  20. Выражения for и строковые директивы
  21. Условная логика: count-трюк, for_each и директива if
  22. Встроенные функции, типы и выражения HCL
  23. Развёртывание без простоя: create_before_destroy
  24. Подводные камни Terraform и рефакторинг с блоком moved
  25. Управление секретами: основы и типы
  26. Инструменты управления секретами: Yandex Lockbox, Vault, SOPS
  27. Аутентификация провайдера и секреты: сервисные аккаунты и OIDC
  28. Секреты в ресурсах и состоянии, ephemeral-значения
  29. Провайдеры Terraform: установка, версии, required_providers
  30. Несколько копий одного провайдера: alias и мультизона
  31. Несколько провайдеров и аккаунтов: configuration_aliases
  32. Terraform, Docker и Kubernetes: Managed Kubernetes в Yandex Cloud
  33. Код Terraform промышленного уровня: почему это долго
  34. Мелкие компонуемые модули вместо монолита
  35. Тестируемые модули и проверки: validation, precondition, postcondition
  36. Версионирование, публикация модулей и Terragrunt
  37. Ручное тестирование Terraform и очистка ресурсов
  38. Автоматические тесты на Terratest: модульные тесты
  39. Интеграционные и сквозные тесты, пирамида тестирования
  40. Нативный terraform test и статический анализ (вы здесь)
  41. Внедрение Terraform в команде: процессы и культура
  42. Конвейер развёртывания прикладного кода
  43. Конвейер инфраструктурного кода и золотое правило Terraform
  44. Стиль, ревью и CI/CD-инструменты: Atlantis, TACOS, policy as code
  45. Что нового в Terraform 1.3-1.10: моды, импорт, провайдер-функции, Stacks
  46. OpenTofu в 2026: чем живёт форк и как мигрировать
  47. Сертификация HashiCorp Terraform Associate и карьера
Признайся честно: как ты до сих пор проверял свои модули? Я угадаю. Запускал terraform plan, щурился в простыню вывода, бормотал "ну вроде нормально" и катил в прод. А когда через месяц коллега менял один default у переменной и всё разваливалось, ты узнавал об этом из алертов, а не из теста. Знакомо?

Инфраструктура как код - это прекрасно ровно до того момента, пока этот код никто не тестирует. А раньше тестировать было больно: единственным взрослым вариантом был Terratest - библиотека на Go, то есть тебе, питонисту или админу, надо было лезть в чужой язык, поднимать go.mod, писать TestMain и реально создавать ресурсы в облаке, чтобы что-то проверить. Половина команды на этом отваливалась.

В этом уроке разберём то, что radикально изменило картину: нативный фреймворк terraform test. Он встроен в сам Terraform, не требует ни строчки Go, а с приходом mock-провайдеров умеет проверять логику без единого реального ресурса в Yandex Cloud. Плюс пройдёмся по статическому анализу - валидации, линтерам и policy as code, которые ловят проблемы ещё до того, как ты вообще что-то применил.

Откуда это взялось и что под капотом

Нативный фреймворк тестирования стал стабильным в Terraform 1.6 (это был конец 2023-го), а уже в 1.7 завезли главную фишку для нашей темы - mock-провайдеры. К середине 2026-го это давно не эксперимент: на актуальных ветках Terraform (1.15.x) и в OpenTofu (он шагнул дальше и сейчас на 1.12.x, тоже со своим terraform test и моками) это рабочий инструмент по умолчанию. То есть если у тебя свежий бинарник - всё уже внутри, ставить ничего не надо.

Идея простая до неприличия. Ты кладёшь рядом с модулем файлы с расширением .tftest.hcl (или JSON-вариант, но HCL читается человеком, давай по-человечески). Внутри - один или несколько блоков run. Каждый run - это отдельный сценарий: задаём переменные, запускаем plan или apply, а потом проверяем результат блоками assert. Запускаешь всё командой terraform test - она сама находит файлы, прогоняет сценарии и в конце честно убирает за собой созданные ресурсы.

Ключевой момент, который путает новичков: у run есть параметр command. Если command = plan - Terraform только считает план и проверяет ассерты по плану, ничего в облаке не трогая. Если command = apply (это значение по умолчанию) - реально создаёт ресурсы, проверяет, а в конце разрушает. Plan-проверки быстрые и бесплатные, apply-проверки честные, но медленные и стоят денег. Баланс между ними - твоё инженерное решение.

Изображение

Первый тест: проверяем план без облака

Допустим, у нас есть модуль, который заводит сеть и виртуалку в Yandex Cloud. Простейший тест на уровне плана - убедиться, что имена и атрибуты вычисляются правильно. Положи это в файл network.tftest.hcl рядом с модулем.

Код: Выделить всё

variables {
  network_name = "test-net"
  zone         = "ru-central1-a"
}

run "validate_network_plan" {
  command = plan

  assert {
    condition     = yandex_vpc_network.this.name == "test-net"
    error_message = "Имя сети должно совпадать с входной переменной"
  }

  assert {
    condition     = yandex_vpc_subnet.this.zone == "ru-central1-a"
    error_message = "Подсеть создаётся не в той зоне"
  }
}
Обрати внимание: внутри condition мы обращаемся к ресурсам напрямую по их адресу - yandex_vpc_network.this, как будто пишем обычный output. Это и есть сила нативного фреймворка - он работает в той же системе типов, что и сам модуль, ничего парсить руками не надо.

Можно подключать переменные на уровне run, объявлять провайдеры, и даже выстраивать цепочки: один run применяет ресурс, следующий run этим результатом пользуется. Так тестируют сценарии вроде "создали кластер, затем накатили на него настройку".

Mock-провайдеры: тестируем логику за секунды

Теперь главный свежак. Даже plan-проверки требуют, чтобы провайдер сходил в API Yandex Cloud, проверил креды, прочитал data-источники. Это медленно и требует доступа в облако из CI. Mock-провайдеры выбивают эту зависимость напрочь.

Ставишь в run (или в самом файле теста) блок mock_provider - и провайдер больше не ходит в сеть. Вместо реальных значений он отдаёт синтетические данные для computed-атрибутов. А если тебе нужно зафиксировать конкретное значение (например, чтобы id ресурса в тесте был предсказуемым), используешь блоки override_resource, override_data и override_module. Их можно писать прямо в тесте либо вынести в отдельный файл с расширением .tfmock.hcl.

Код: Выделить всё

mock_provider "yandex" {}

run "logic_without_cloud" {
  command = plan

  override_data {
    target = data.yandex_compute_image.ubuntu
    values = {
      id = "fd8mock0imageid000"
    }
  }

  assert {
    condition     = yandex_compute_instance.vm.boot_disk[0].initialize_params[0].image_id == "fd8mock0imageid000"
    error_message = "VM должна подхватывать image_id из data-источника"
  }
}
Что мы тут сделали: сказали "провайдер yandex - мок, в облако не ходи", а data-источнику с образом Ubuntu подсунули фиксированный id. Теперь тест проверяет ЛОГИКУ модуля - что image_id из data корректно прорастает в диск ВМ - и делает это за доли секунды, без кредов, без интернета, без копейки расходов. Вот это и есть то, ради чего стоило городить весь фреймворк.

Terraform test против Terratest: когда что

Раз уж есть нативный инструмент, нужен ли вообще Terratest? Нужен, но реже. Раскладка простая.
  • terraform test - бери по умолчанию. Юнит-логика модулей, проверка планов, валидация переменных, быстрые сценарии на моках. Не требует Go, живёт рядом с кодом, читается любым, кто знает HCL.
  • Terratest - когда нужна тяжёлая интеграция за пределами Terraform. Например, поднять инфру, потом сходить по HTTP на развёрнутый сервис, проверить ответ, дёрнуть SDK облака, выполнить SSH-команду на ВМ. Всё, что выходит за рамки "проверить значения в плане/состоянии", - это территория Go и Terratest.
Грубо: terraform test отвечает на вопрос "правильно ли мой модуль ДУМАЕТ", Terratest - "правильно ли то, что он СОЗДАЛ, реально работает".

Статический анализ: ловим беду до запуска

Тесты тестами, но дешевле всего отлавливать проблемы вообще без выполнения - статикой. Вот твой минимальный джентльменский набор.
  • terraform fmt - форматирование. В CI запускай как terraform fmt -check -recursive, чтобы пайплайн краснел на кривых отступах.
  • terraform validate - проверка синтаксиса и внутренней согласованности конфигурации без обращения в облако. Дешёвый первый барьер.
  • tflint - линтер. Знает про специфику провайдеров через плагины, ругается на устаревшие конструкции, неиспользуемые переменные, подозрительные значения.
  • Безопасность: tfsec (давно влился в Trivy, так что чаще запускают именно trivy config) и checkov - сканируют HCL на небезопасные настройки: открытые наружу порты, отсутствие шифрования, публичные бакеты.
  • Policy as code: OPA/Conftest (политики на языке Rego) и Sentinel (родной для платных тиров HashiCorp). Это уже про правила твоей организации: "запрещаем ресурсы без тега команды", "только разрешённые типы машин".
Важно не путать слои. Линтеры и security-сканеры смотрят на текст конфигурации. Policy as code часто работает по JSON-плану (terraform show -json) - то есть видит уже вычисленный результат и может судить о реальных значениях. А terraform test проверяет поведение. Эти штуки не конкурируют, а складываются в эшелонированную оборону.

Собираем в CI

Порядок шагов в пайплайне выстраивается от дешёвого к дорогому - чтобы быстрые проверки роняли сборку раньше, чем ты потратишь время на тяжёлые.

Код: Выделить всё

# Псевдо-пайплайн, шаги по нарастанию стоимости
terraform fmt -check -recursive      # стиль, миллисекунды
terraform init -backend=false        # без подключения к state
terraform validate                   # синтаксис и схема
tflint --recursive                   # линт
trivy config .                       # безопасность (бывший tfsec)
checkov -d .                         # ещё безопасность, другой набор правил
terraform test                       # нативные тесты, в т.ч. на моках
Тесты на моках можно гонять на каждый пуш - они быстрые. Полноценные apply-тесты в реальном Yandex Cloud разумно держать на отдельной ветке пайплайна или по расписанию, чтобы не жечь квоты на каждый коммит.

Типичные грабли
  • Думать, что mock_provider создаёт ресурсы. Нет. Мок ничего не создаёт и не валидирует против реального API. Если в модуле опечатка в имени атрибута, которую отловил бы только настоящий провайдер, мок может её пропустить. Моки - про логику, не про правду облака.
  • Все тесты делать на apply. command = apply по умолчанию - и люди забывают это переопределить. В итоге простейший юнит-тест поднимает кластер на пять минут. Где можно - ставь command = plan.
  • Путать override_* с переменными. override_resource/override_data подменяют значения уже существующих в конфигурации ресурсов и data-источников, а не объявляют новые. Target должен указывать на реальный адрес из модуля.
  • Гонять security-сканеры, но игнорить их вывод. checkov и trivy найдут десятки замечаний на свежем проекте. Не надо чинить всё сразу, но надо явно решить, что подавляешь и почему, иначе CI превратится в постоянно красную лампочку, на которую все забили.
  • Забыть про init перед validate. terraform validate требует инициализированных модулей и провайдеров. В CI делай init -backend=false, чтобы не дёргать удалённый state ради простой проверки схемы.
Мини-лаба

Повтори руками, на любом своём маленьком модуле:
  • Создай файл basic.tftest.hcl с одним run на command = plan и хотя бы двумя assert по атрибутам твоих ресурсов. Запусти terraform test.
  • Добавь второй run с mock_provider "yandex" {} и одним override_data или override_resource с фиксированным id. Убедись, что он отрабатывает без кредов облака.
  • Прогони по модулю terraform fmt -check, terraform validate, а потом tflint и checkov. Посмотри, что они скажут, и реши, что из этого реальная проблема.
  • Собери из этих команд один shell-скрипт в правильном порядке - получился твой локальный мини-CI.
Контрольные вопросы
  • Чем по результату отличается run с command = plan от run с command = apply, и когда какой выбирать?
  • Что именно делает mock_provider и какой класс ошибок он принципиально НЕ способен поймать?
  • Для чего нужны блоки override_resource, override_data и override_module - и чем они отличаются от объявления переменных?
  • В каких задачах нативный terraform test проигрывает Terratest и почему?
Итог: что забрать с собой

Нативный terraform test - твой инструмент по умолчанию для проверки модулей: HCL-файлы .tftest.hcl, блоки run и assert, никакого Go. Mock-провайдеры (mock_provider плюс override_*) позволяют проверять логику инфраструктуры как кода за секунды, без реальных ресурсов в Yandex Cloud и без затрат - это и есть главный сдвиг последних версий. Terratest оставь для тяжёлой интеграции вне Terraform. А поверх тестов выстрой статику: fmt и validate как дешёвый фундамент, tflint как линтер, trivy/checkov для безопасности, OPA или Sentinel для policy as code. Выстрой это в CI от дешёвого к дорогому - и твои terraform plan и apply перестанут быть лотереей.
👍2 ❤️3 🔥 😄 🤔
Аватара пользователя
ziguser
Сообщения: 1
Зарегистрирован: 15 май 2026, 23:12

Re: Нативный terraform test и статический анализ

Сообщение ziguser »

Спасибо, наконец дошло зачем нужен command = plan. Я раньше все тесты на apply гонял и не понимал почему пайплайн по 10 минут висит и квоту жрёт.
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
maverick14
Сообщения: 1
Зарегистрирован: 11 май 2026, 07:17

Re: Нативный terraform test и статический анализ

Сообщение maverick14 »

А мок-провайдер можно один раз объявить на весь файл, или его в каждом run-блоке прописывать надо? И tflint реально проверяет именно ресурсы yandex или только общий синтаксис?
👍 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Интеграционные и сквозные тесты, пирамида тестирования
Следующая глава →
Внедрение Terraform в команде: процессы и культура

Все главы курса «Terraform: инфраструктура как код на Yandex Cloud»

Поделиться темой: ✈ Telegram VK
Похожие запросы: terraform yandex cloud с чего начать новичкукак установить terraform и opentofu на linuxчто такое terraform state и tfstate простыми словамиудаленный backend terraform на object storage yandex cloudчто такое инфраструктура как код iac простыми словамиterraform plan и apply что делают и чем отличаются

Вернуться в «Terraform: инфраструктура как код на Yandex Cloud»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость