Terraform и IaC
Жизненный цикл plan/apply, удалённый state и блокировки, дрейф и import, модули, count против for_each, workspace, taint/replace и безопасный рефакторинг state.
13 вопросов
JuniorТеорияОчень частоЧто такое Terraform и что делают plan и apply в его цикле?
Что такое Terraform и что делают plan и apply в его цикле?
Terraform — декларативный Infrastructure-as-Code инструмент: вы описываете желаемое состояние в HCL, а он приводит реальную инфраструктуру к нему. plan показывает разницу конфига и state, ничего не меняя; apply применяет эту разницу — создать, изменить или удалить — и пишет результат в state.
Типичные ошибки
- ✗Думать, что
applyработает без предварительного диффа в стиле plan - ✗Считать, что Terraform меняет инфраструктуру по шагам, как shell-скрипт
- ✗Полагать, что
planменяет реальные ресурсы, а не только показывает превью
Уточняющие вопросы
- →Почему применять сохранённый plan-файл в CI безопаснее, чем голый
apply? - →Что делает Terraform, когда конфиг точно совпадает со state?
JuniorТеорияОчень частоЧто такое файл state в Terraform и зачем он нужен?
Что такое файл state в Terraform и зачем он нужен?
State сопоставляет каждый ресурс конфига с реальным объектом, который создал Terraform, и его атрибуты. Это источник истины, с которым сравнивает plan — поэтому его нельзя терять или править руками. Значения хранятся в открытом виде, включая секреты, так что state надо защищать.
Типичные ошибки
- ✗Коммитить локальный
terraform.tfstateв Git, раскрывая секреты открытым текстом - ✗Править state руками ради починки ресурса вместо команд Terraform
- ✗Считать state одноразовым кэшем, который Terraform заново соберёт живьём
Уточняющие вопросы
- →Почему удалённый зашифрованный бэкенд лучше локального файла state?
- →Что ломается, если у двух инженеров разошлись копии одного state?
JuniorТеорияЧастоЧто такое дрейф (drift) в Terraform и как terraform plan его обнаруживает?
Что такое дрейф (drift) в Terraform и как terraform plan его обнаруживает?
Дрейф — это расхождение реальной инфраструктуры с тем, что записано в state, обычно из-за изменения вне Terraform, например правки в консоли. plan обновляет данные, читая живые атрибуты каждого ресурса, сравнивает их с конфигом и показывает разницу, которую свёл бы.
Типичные ошибки
- ✗Думать, что дрейф — это изменение HCL-конфига, а не реального ресурса
- ✗Считать, что
planсравнивает лишь снимки и никогда не читает живой state - ✗Полагать, что Terraform блокирует все изменения в обход, сделанные в консоли
Уточняющие вопросы
- →Когда вы приняли бы дрейф в state через
apply -refresh-only? - →Как
ignore_changesв блокеlifecycleвзаимодействует с ожидаемым дрейфом?
MiddleТеорияЧастоcount против for_each — что пересоздаёт ресурсы при изменении списка и почему?
count против for_each — что пересоздаёт ресурсы при изменении списка и почему?
count индексирует ресурсы по позиции, поэтому удаление или вставка в середину сдвигает все последующие индексы — Terraform видит новые адреса и уничтожает и пересоздаёт их. for_each ключует по стабильному ключу set или map, поэтому изменение одной записи трогает только её, а порядок неважен.
Типичные ошибки
- ✗Использовать
countнад списком, у которого могут удаляться средние элементы - ✗Думать, что перестановка списка в
count— безобидный no-op - ✗Считать
countиfor_eachвзаимозаменяемыми по поведению
Уточняющие вопросы
- →Как мигрировать ресурс с
countнаfor_each, не уничтожив его? - →Какой ключ вы выбрали бы для
for_eachнад списком объектов?
MiddleТеорияЧастоКак взять существующий ресурс под Terraform — блок import против CLI?
Как взять существующий ресурс под Terraform — блок import против CLI?
import берёт существующий ресурс под управление — записывает реальный объект в state по адресу из конфига, ничего не создавая. Форма CLI меняет state сразу; новый блок import декларативен и проходит code review. В обоих случаях сам ресурсный блок вы всё равно пишете руками.
Типичные ошибки
- ✗Ожидать, что
importсгенерирует за вас HCL-конфиг ресурса - ✗Думать, что
importсоздаёт или пересобирает реальный ресурс - ✗Забыть написать ресурсный блок до импорта
Уточняющие вопросы
- →Почему несоответствие конфига после импорта даёт ложный replace на следующем плане?
- →Чем блоки
importпомогают ревьюить крупную адаптацию в pull request?
MiddleТеорияЧастоЧто такое модуль Terraform и что делает его хорошим переиспользуемым блоком?
Что такое модуль Terraform и что делает его хорошим переиспользуемым блоком?
Модуль — переиспользуемая папка ресурсов с чётким интерфейсом из входных переменных и выходов. Хороший модуль узкий и композируемый: открывает только осмысленные входы, возвращает полезные выходы, ничего не хардкодит под окружение и версионируется, чтобы вызывающий закреплял известный релиз.
Типичные ошибки
- ✗Хардкодить значения под окружение вместо приёма их как входов
- ✗Брать модуль как
latestвместо закрепления версии - ✗Открывать каждый внутренний ресурс вместо небольшого набора выходов
Уточняющие вопросы
- →Почему закреплять версию модуля, а не отслеживать основную ветку?
- →Как компоновать маленькие модули, не создавая глубокую цепочку зависимостей?
MiddleТеорияЧастоЧто такое удалённый state и зачем Terraform блокирует его во время apply?
Что такое удалённый state и зачем Terraform блокирует его во время apply?
Удалённый state хранит файл в общем зашифрованном бэкенде вместо локального диска, чтобы у команды был один источник истины. Во время apply Terraform берёт блокировку; без неё два одновременных apply смешают записи и повредят state, начав неверно отслеживать ресурсы.
Типичные ошибки
- ✗Держать state на локальном диске, пока несколько инженеров применяют один конфиг
- ✗Считать одновременные apply безопасными, потому что записи якобы атомарны
- ✗Полагать, что блокировка нужна для скорости, а не для корректности
Уточняющие вопросы
- →Как бэкенд S3 реализует блокировку через таблицу блокировок DynamoDB?
- →Что такое
terraform force-unlockи когда его опасно применять?
MiddleТеорияЧастоЧто такое workspace в Terraform и каковы их ограничения для мультисредовых конфигураций?
Что такое workspace в Terraform и каковы их ограничения для мультисредовых конфигураций?
Workspace — именованный отдельный state с общими конфигом и бэкендом, так dev и prod держат разный state. Но изоляция слабая — общий бэкенд и креды, поэтому apply не в том workspace достаёт до prod. Для сильной изоляции берут отдельные конфиги на окружение.
Типичные ошибки
- ✗Считать workspace сильной продовой изоляцией, несмотря на общий бэкенд
- ✗Думать, что у каждого workspace может быть свой бэкенд или креды
- ✗Путать CLI-workspace с workspace в Terraform Cloud
Уточняющие вопросы
- →Когда workspace разумны — эфемерные или пер-разработчик стеки?
- →Почему отдельные бэкенды дают более сильную изоляцию радиуса поражения, чем workspace?
MiddleДебаггингИногдаКто-то изменил ресурс в консоли облака, и plan хочет откатить это — объясните и решите
Кто-то изменил ресурс в консоли облака, и plan хочет откатить это — объясните и решите
Terraform обнаружил дрейф — консоль выставила t3.large, а конфиг всё ещё говорит t3.small, поэтому plan возвращает реальность к коду. Чтобы сохранить значение из консоли, обновите конфиг до t3.large или добавьте ignore_changes для него. Чтобы отбросить — просто apply. State руками не правьте.
Типичные ошибки
- ✗Править
terraform.tfstateруками под значение из консоли - ✗Делать
taintресурса, форся ненужное уничтожение и пересоздание - ✗Считать, что живая инфраструктура всегда важнее конфига
Уточняющие вопросы
- →Когда
apply -refresh-only— верный способ принять правку из консоли? - →Чем
ignore_changesотличается от удаления атрибута из конфига?
MiddleДизайнИногдаВаша организация ведёт dev, staging и prod для дюжины сервисов силами двух команд, и вам нужно спроектировать репозиторий и раскладку state в Terraform. Требования: общие инфраструктурные модули, переиспользуемые во всех окружениях; каждое окружение изолировано, чтобы ошибочный apply в dev никогда не задел state prod; отдельные удалённые бэкенды на каждое окружение с блокировкой и least-privilege кредами; ясный путь продвижения от dev к prod; и безопасная работа двух команд без конкуренции за блокировку одного гигантского state. Опишите структуру репозитория, как вы дробите state, как модули делятся и версионируются и как держать радиус поражения малым. Код не пишите.
Ваша организация ведёт dev, staging и prod для дюжины сервисов силами двух команд, и вам нужно спроектировать репозиторий и раскладку state в Terraform. Требования: общие инфраструктурные модули, переиспользуемые во всех окружениях; каждое окружение изолировано, чтобы ошибочный apply в dev никогда не задел state prod; отдельные удалённые бэкенды на каждое окружение с блокировкой и least-privilege кредами; ясный путь продвижения от dev к prod; и безопасная работа двух команд без конкуренции за блокировку одного гигантского state. Опишите структуру репозитория, как вы дробите state, как модули делятся и версионируются и как держать радиус поражения малым. Код не пишите.
Вынесите общую инфру в версионируемые модули, закреплённые на каждое окружение. Дайте каждому окружению свой корневой конфиг и удалённый бэкенд с блокировкой и least-privilege кредами — радиус поражения одно окружение. Дробите state по сервисам против конкуренции за блокировку, продвигая подъёмом закреплённых версий от dev к prod.
Типичные ошибки
- ✗Держать все окружения в одном общем state и бэкенде
- ✗Изолировать окружения только workspace вместо отдельных бэкендов
- ✗Делить один широкий креденшл на dev, staging и prod
Уточняющие вопросы
- →Где вы провели бы границы state — по сервису, по слою или по команде?
- →Чем продвижение через закреплённые версии лучше прямой правки конфига prod?
MiddleДебаггингИногдаterraform apply падает с Error acquiring the state lock — диагностируйте и безопасно решите
terraform apply падает с Error acquiring the state lock — диагностируйте и безопасно решите
Блокировка бэкенда защищает state от одновременных записей. Отменённый запуск умер, не сняв блокировку, поэтому она застряла — на деле никто не применяет. Убедитесь по полям Who/Created, что apply не идёт, затем — terraform force-unlock с показанным ID. Не снимайте силой вслепую.
Типичные ошибки
- ✗Снимать блокировку силой, не проверив, идёт ли apply
- ✗Удалять файл state или таблицу блокировок, чтобы убрать ошибку
- ✗Считать, что блокировка сама истекает по таймауту
Уточняющие вопросы
- →Почему слепой
force-unlockопасен во время реального одновременного apply? - →Как таблица блокировок DynamoDB упорядочивает apply над бэкендом S3?
SeniorКодИногдаПереименуйте ресурс Terraform без уничтожения/пересоздания — допишите блок moved
Переименуйте ресурс Terraform без уничтожения/пересоздания — допишите блок moved
Добавьте блок moved, сопоставляющий старый адрес aws_instance.web с новым aws_instance.app. На следующем plan Terraform перепишет адрес в state, поэтому ничего не уничтожается и не создаётся. Это декларативно и ревьюится, в отличие от разового terraform state mv.
Типичные ошибки
- ✗Считать, что голое переименование сопоставляется по атрибутам, а не по адресу
- ✗Хвататься за
terraform state mvвместо ревьюируемого блокаmoved - ✗Думать, что
prevent_destroyвыполняет переименование
Уточняющие вопросы
- →Когда разовый
terraform state mvвсё же уместнее блокаmoved? - →Чем блоки
movedпомогают при выносе ресурсов в модуль?
SeniorДебаггингИногдаПосле апгрейда провайдера plan хочет заменить живую базу — диагностируйте и избегите потери данных
После апгрейда провайдера plan хочет заменить живую базу — диагностируйте и избегите потери данных
Мажор провайдера меняет, какой атрибут форсит замену — здесь engine_version теперь вызывает replace. Прочтите upgrade guide. Избегите уничтожения — ignore_changes или prevent_destroy, косметику сведите через -refresh-only. Не применяйте replace на живой БД вслепую.
Типичные ошибки
- ✗Применять replace
-/+на stateful-ресурсе, не разобравшись - ✗Считать, что апгрейд провайдера никогда не форсит замену
- ✗Думать, что
ignore_changesне может остановить форсированную замену
Уточняющие вопросы
- →Как
create_before_destroyснижает простой, когда замена неизбежна? - →Почему читать upgrade guide провайдера до подъёма мажорной версии?