Когда запуск Terraform с ноутбука перестаёт быть достаточным

Вы управляли инфраструктурой с помощью Terraform из своего терминала. Пока вы единственный, кто вносит изменения, всё работает отлично. Вы запускаете terraform plan, проверяете вывод, выполняете terraform apply и двигаетесь дальше. Файл состояния лежит на вашей машине, и вы точно знаете, что и когда изменили.

Затем к проекту присоединяется коллега. Он клонирует репозиторий, запускает terraform init и получает другой план, нежели вы видели вчера. Файл состояния на его ноутбуке устарел. Кто-то применяет изменения, никого не предупредив. Через неделю никто не помнит, кто изменил правила группы безопасности и зачем.

Это тот самый момент, когда workflow на основе ноутбука ломается. Проблемы не в самом Terraform. Они в координации, прозрачности и подотчётности. Когда инфраструктура общая, запуск команд с отдельных машин порождает путаницу, риски и незаметный дрейф.

Перенос workflow в пайплайн

Вместо того чтобы запускать terraform plan и terraform apply с ноутбука каждого разработчика, вы можете перенести этот workflow в CI/CD пайплайн. Тогда каждое изменение инфраструктуры проходит один и тот же путь, фиксируется и может быть проверено командой до того, как вступит в силу.

Подход с пайплайном превращает изменения инфраструктуры в нечто похожее на изменения кода приложения. Вы пишете конфигурацию, открываете pull request, получаете обратную связь, и только после утверждения изменение применяется. Разница в том, что Terraform добавляет этап планирования, который показывает, что именно произойдёт с вашими облачными ресурсами, прежде чем что-то выполнится.

Следующий пример показывает типовую конфигурацию CI пайплайна, реализующую workflow write-plan-apply:

stages:
  - validate
  - plan
  - apply

validate:
  stage: validate
  script:
    - terraform fmt -check
    - terraform validate
  only:
    - merge_requests

plan:
  stage: plan
  script:
    - terraform plan -out=plan.tfplan
  artifacts:
    paths:
      - plan.tfplan
  only:
    - merge_requests

apply:
  stage: apply
  script:
    - terraform apply plan.tfplan
  when: manual
  only:
    - main

Три этапа: Write, Plan, Apply

Самый распространённый способ интеграции Terraform в пайплайн — разбить workflow на три этапа, соответствующие естественному ходу внесения изменений.

Следующая диаграмма последовательности иллюстрирует взаимодействие трёх этапов:

sequenceDiagram participant Dev as Разработчик participant PR as Pull Request participant Pipe as CI Пайплайн participant Rev as Ревьюер participant Infra as Инфраструктура Dev->>PR: Открывает PR с изменениями конфигурации PR->>Pipe: Запускает пайплайн Pipe->>Pipe: Этап Write (fmt, validate) Pipe->>PR: Публикует вывод плана как комментарий PR->>Rev: Запрашивает ревью Rev->>PR: Утверждает или отклоняет alt Утверждено PR->>Pipe: Мерж в main запускает apply Pipe->>Infra: terraform apply (сохранённый план) Infra-->>Pipe: Ресурсы обновлены Pipe-->>Dev: Уведомление об успехе else Отклонено PR-->>Dev: Запрошены изменения end

Write: выявить проблемы до ревью

Этап Write начинается, когда кто-то изменяет файлы конфигурации Terraform и открывает pull request. На этом этапе пайплайн может автоматически выполнить базовые проверки. terraform fmt проверяет, что код соответствует стандартному форматированию. terraform validate проверяет синтаксическую корректность конфигурации и наличие всех обязательных аргументов.

Эти проверки — инфраструктурный аналог запуска линтера для кода приложения. Они выявляют простые ошибки на ранней стадии, до того, как человек-ревьюер потратит время на просмотр pull request. Если форматирование неверное или обязательное поле отсутствует, пайплайн сразу падает, и автор исправляет проблему до того, как кто-то ещё подключится.

Plan: показать, что изменится

После открытия pull request пайплайн автоматически запускает terraform plan. Вывод плана публикуется как комментарий к pull request. Именно здесь ревью становится осмысленным.

Вывод плана показывает в точности, что сделает Terraform: какие ресурсы будут созданы, какие изменены, а какие уничтожены. Ревьюер видит, что pull request меняет тип инстанса сервера с small на medium, добавляет новое правило файрвола или удаляет старую подсеть для базы данных. Если что-то выглядит не так, ревьюер отклоняет pull request до того, как изменение попадёт в продакшен.

Этот этап критически важен, потому что он переводит ревью инфраструктуры из формата «поверь мне, я запустил план» в формат «вот план, проверь его сам». План становится частью обсуждения в pull request, и решение об утверждении или отклонении принимается на основе конкретного вывода, а не на доверии.

Apply: выполнить только после утверждения

Этап Apply запускается только после того, как pull request утверждён и смерджен в основную ветку. Пайплайн в основной ветке затем выполняет terraform apply, используя план, который уже был проверен.

Самый безопасный способ сделать это — сохранить вывод плана с предыдущего этапа как файл и передать этот файл в terraform apply. Этот метод называется сохранённым планом (saved plan). Он гарантирует, что apply выполнит именно те изменения, которые были проверены, а не новый план, который может отличаться из-за того, что кто-то запушил другой коммит между ревью и apply.

Без сохранённого плана пайплайн запускал бы terraform plan заново на этапе apply. Если конфигурация тем временем изменилась, новый план может отличаться от проверенного. Это сводит на нет смысл ревью.

Управление состоянием в пайплайне

Управление состоянием становится простым, когда Terraform запускается в пайплайне. Файл состояния должен храниться в общем месте, например, в облачном хранилище или в бэкенде Terraform, который команда настраивает один раз. Каждый раз, когда пайплайн запускает plan или apply, он получает состояние из этого общего места, а не из локальной копии, которая может быть устаревшей.

Пайплайн также должен включать блокировку состояния. Terraform может блокировать файл состояния, пока выполняется plan или apply, предотвращая одновременное изменение состояния двумя процессами. Без блокировки два пайплайна могут запустить apply одновременно, что приведёт к повреждению или неожиданным результатам.

Что даёт этот workflow

Как только workflow write-plan-apply работает в пайплайне, изменения инфраструктуры подчиняются той же дисциплине, что и изменения кода приложения. Каждое изменение проходит через pull request, проверяется членами команды, тестируется автоматическим планом и выполняется только после утверждения. Вся история изменений фиксируется в Git и в логах пайплайна.

Вы больше не гадаете, кто изменил сервер и когда это произошло. Вы больше не беспокоитесь об устаревших файлах состояния на чьём-то ноутбуке. Вы больше не слышите «у меня это работает» в отношении инфраструктуры.

Практический чеклист для настройки

  • Настройте удалённый бэкенд для хранения состояния до настройки пайплайна. Бэкенд должен быть доступен раннеру пайплайна.
  • Настройте блокировку состояния. Большинство бэкендов, такие как S3 с DynamoDB или GCS с версионированием объектов, поддерживают это из коробки.
  • Добавьте terraform fmt и terraform validate как ранние проверки в пайплайне pull request.
  • Запускайте terraform plan для каждого pull request и публикуйте вывод как комментарий.
  • Используйте сохранённые планы. Сохраняйте файл плана как артефакт пайплайна и передавайте его на этап apply.
  • Ограничьте выполнение terraform apply только основной веткой после мержа.
  • Убедитесь, что у раннера пайплайна есть минимально необходимые разрешения для выполнения plan и apply. Не используйте учётные данные администратора.

Что дальше

После того как пайплайн автоматически обрабатывает workflow write-plan-apply, следующий вопрос — как управлять разными окружениями. Стейдж и продакшен редко используют одинаковые значения конфигурации. Пайплайну нужно обрабатывать переменные, специфичные для окружения, файлы состояния и шлюзы утверждения, не дублируя весь workflow для каждого окружения.

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