сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · Terraform и Ansible

Terraform: план, провайдеры, версии

Terraform: план, провайдеры, версии

Поднял стенд и прогнал всё руками. Команда просмотра плана сказала «будет создано 3 ресурса» - и на диске не появилось ни одного файла. Команда применения создала три. Повторный просмотр плана ответил «No changes. Your infrastructure matches the configuration». Три команды - и видно всё устройство инструмента: он сравнивает описанное с существующим и показывает разницу до того, как что-то тронуть.

Стержень: инструмент не выполняет шаги, а приводит реальность к описанию; план - это предъявленная разница, которую читают ДО применения.

// Формулировки: «что делает plan?», «зачем закреплять версии провайдеров?», «чем декларативный подход отличается от скрипта?»

// Всё в этой теме проверено на OpenTofu - открытом форке Terraform с тем же языком и теми же командами.

Описание вместо шагов

Ресурс тут - единица описания: сервер, сеть, база, правило доступа, файл. Скрипт выполняет шаги над ними: создай, положи, запусти. Запусти его дважды - и получишь либо ошибку «уже существует», либо второй экземпляр. Описательный подход устроен иначе: вы записываете, что должно быть, а инструмент сам решает, что для этого сделать - создать, изменить или не трогать.

Отсюда и главное свойство, которое я проверил: повторное применение ничего не делает. Первый прогон создал три файла, второй ответил, что расхождений нет. Это позволяет запускать применение сколько угодно раз, в том числе после обрыва посередине.

// План - отдельная команда и отдельная привычка. Он показывает разницу и не трогает ничего: после просмотра плана на диске было ноль файлов. Читать план перед применением - базовая дисциплина: именно там видно строку «будет уничтожено 2 ресурса», которую никто не заказывал.

описательный подход
записываем нужное состояние, а не шаги до него
план
предъявленная разница между описанием и реальностью; ничего не меняет

Провайдеры и закрепление версий

Сам инструмент ничего не умеет: работу делают провайдеры - модули, которые знают, как разговаривать с конкретной системой. Провайдер облака, провайдер базы, провайдер локальных файлов. Они скачиваются при подготовке рабочего каталога и записываются в файл замков.

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

// Отсюда практика: файл замков коммитят в репозиторий, версии указывают точно, а обновление провайдеров делают отдельным изменением, с планом и глазами. Обновлять инструмент вместе с релизом продукта - плохая идея: если что-то пойдёт не так, вы будете разбирать сразу две проблемы.

провайдер
модуль, который умеет создавать и менять ресурсы конкретной системы
файл замков
запись точных версий провайдеров; коммитится в репозиторий

Что читать в плане

План говорит на своём языке, и его стоит понимать буквально. Строка с плюсом - создание. С минусом - уничтожение. С тильдой - изменение на месте. А вот сочетание минуса и плюса означает замену: ресурс будет уничтожен и создан заново, и если это база данных, то вместе с данными.

Итоговая строка вида «Plan: 1 to add, 0 to change, 2 to destroy» - главное, что смотрят перед применением. Я специально ловил такой случай: удаление одного элемента из списка дало план с двумя уничтожениями и одним созданием, хотя в описании изменилась одна строчка.

// Поэтому в конвейере - наборе шагов, через который проходит каждое изменение, - план публикуют прямо в изменение комментарием, а применение делают отдельным шагом с ручным подтверждением там, где ресурсы дорогие. И отдельно ставят проверку: если план содержит уничтожение, требуется вторая пара глаз.

замена ресурса
уничтожить и создать заново; для базы означает потерю данных
итог плана
строка «сколько добавить, изменить, уничтожить»; читается всегда

Как отвечать: «Что делает команда plan и зачем она нужна, если есть apply?»

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

Ответ объясняет назначение, расшифровывает язык плана и заканчивается процессом. Пример с неожиданным уничтожением показывает, зачем это всё нужно на самом деле.

На чём валятся

  • Применяют изменения не глядя в план и обнаруживают уничтожение постфактум.
  • Не различают изменение на месте и замену ресурса.
  • Не закрепляют версии провайдеров: обновление меняет умолчания и предлагает пересоздать половину.
  • Не коммитят файл замков, и у каждого своя версия провайдера.
  • Обновляют версию инструмента вместе с релизом продукта и разбирают две проблемы разом.

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 8, остальные разбираются в тренажёре.

  1. #dvo_tf_basics1 / 5
    В российском контуре terraform init падает на скачивании провайдера из публичного реестра. Как это решают?
    A)Складывают бинарь провайдера в репозиторий проекта
    B)Снимают пины версий и берут, что скачалось
    C)Собирают провайдер из исходников при каждом init
    D)Поднимают зеркало реестра или локальный каталог провайдеров
    показать ответ и разбор
    +D)Поднимают зеркало реестра или локальный каталог провайдеров

    // разбор: Публичные реестры к 2026 ограничивают доступ из России, а провайдеров отечественных облаков там может не быть вовсе. Штатный механизм — зеркала: сетевое зеркало во внутреннем артефактории или каталог провайдеров на диске, прописанный в конфигурации CLI. Тогда init берёт бинари изнутри периметра, сборки перестают зависеть от внешней доступности, а версии остаются зафиксированными.

  2. #dvo_tf_basics2 / 5
    Коллега создал сервер руками в консоли облака. Terraform его «не видит» и при apply хочет создать свой. Почему?
    A)Terraform игнорирует ресурсы, созданные в веб-консоли
    B)Провайдер не успел просканировать облако на новые ресурсы
    C)Terraform управляет лишь тем, что есть в его state
    D)Ручной ресурс создан в другом регионе, поэтому не виден
    показать ответ и разбор
    +C)Terraform управляет лишь тем, что есть в его state

    // разбор: Terraform знает только ресурсы, записанные в его state, и сверяет с ними конфигурацию. Ресурс, созданный вручную (или другим инструментом), в state отсутствует — для terraform его как будто нет, поэтому по конфигу он захочет создать свой. Чтобы «усыновить» существующий, его импортируют в state (terraform import / import-блок), написав под него конфигурацию.

  3. #dvo_tf_basics3 / 5
    Есть боевой ресурс, созданный руками. Нужно взять его под управление Terraform, не пересоздавая. Как?
    A)terraform import: привязать ресурс к state
    B)Просто описать его в коде и сделать apply
    C)Удалить ресурс и дать terraform создать его заново
    D)Скопировать чужой state-файл с этим ресурсом к себе
    показать ответ и разбор
    +A)terraform import: привязать ресурс к state

    // разбор: terraform import привязывает существующий облачный ресурс к адресу в state, не трогая сам ресурс. Порядок: описать ресурс в конфиге (или сгенерировать), затем terraform import <адрес> <id> (или import-блок с плановой генерацией конфига в новых версиях). После этого plan должен показывать «без изменений» — значит конфиг совпал с реальностью. Пересоздавать боевой ресурс не нужно.

  4. #dvo_tf_basics4 / 5
    Тот же код время от времени даёт другой план, хотя правок не было. Как сделать планы предсказуемыми?
    A)Запускать terraform init -upgrade перед каждым планом
    B)Держать провайдеры последних версий, чтобы не отставать
    C)Отключить проверку версий провайдеров совсем
    D)Закрепить версии провайдеров и коммитить lock-файл
    показать ответ и разбор
    +D)Закрепить версии провайдеров и коммитить lock-файл

    // разбор: «Плавающий» план обычно от того, что подтянулась новая версия провайдера/модуля с изменённым поведением или дефолтами. Лечится закреплением: required_providers с оператором версий и коммит .terraform.lock.hcl в репозиторий — тогда все и CI берут одни и те же версии, и план воспроизводим. Обновление версий делают осознанно (init -upgrade) и ревьюят получившийся diff.

  5. #dvo_tf_basics5 / 5
    Что означает подход «инфраструктура как код»?
    A)Серверы и сети описывают файлами в репозитории и разворачивают по ним
    B)Инфраструктуру настраивают вручную, но записывают шаги в документацию
    C)Приложение и инфраструктуру пишут на одном языке программирования
    D)Код приложения хранят прямо на серверах, минуя сборку
    показать ответ и разбор
    +A)Серверы и сети описывают файлами в репозитории и разворачивают по ним

    // разбор: Описание живёт в git наравне с кодом: его ревьюят, версионируют и катят инструментом. Отсюда и главная выгода — окружение воспроизводится из файла, а не из памяти инженера, который его когда-то настраивал.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.