Состояние Terraform и дрейф
Проверил две вещи подряд. Первая: подправил созданный файл руками - и следующий же план заметил расхождение, а применение вернуло файл к описанному виду. Вторая: удалил файл состояния - и план тут же предложил создать ВСЕ ресурсы заново, хотя они на месте. Инструмент видит мир не напрямую, а через свою записную книжку.
Стержень: состояние - это сопоставление «что в описании» и «что создано в реальности»; без него инструмент слеп, а вместе с ним появляются свои правила обращения.
// Формулировки: «зачем нужен файл состояния?», «что будет, если его потерять?», «как чинить ручные правки?»
Зачем состояние вообще нужно
В описании ресурс - сервер, сеть, файл, правило - называется по-человечески. В реальном облаке у него длинный идентификатор. Состояние хранит связку между одним и другим - без неё инструмент не знает, что этот вот сервер и есть тот самый ресурс из описания.
Отсюда прямое следствие, которое я воспроизвёл: удалил файл состояния, файлы при этом остались на диске, и план предложил создать их заново - «Plan: 2 to add». В облаке это означало бы дубли серверов и второй счёт за них. Возвращение состояния из копии вернуло и правильный ответ: «расхождений нет».
// Отсюда правила обращения. Состояние хранят в общем хранилище с замком - механизмом, который не даёт двум применениям идти одновременно, - а не в репозитории и не на ноутбуке: иначе два одновременных применения затрут записи друг друга. Включают версионирование хранилища, чтобы можно было откатиться. И ⚠ отдельно помнят про секреты: я положил пароль в содержимое ресурса и нашёл его в файле состояния открытым текстом. Состояние - чувствительный файл, доступ к нему выдают как к паролям.
- состояние
- связка между ресурсами из описания и реально созданными объектами
- общее хранилище состояния
- место с замком, откуда состояние читают все; не репозиторий
Дрейф и ручные правки
Дрейф - это расхождение между описанием и реальностью, возникшее мимо инструмента. Кто-то поднял лимит в консоли облака в аварию, кто-то поправил файл руками. Мой замер: правка созданного файла привела к тому, что план увидел расхождение, а применение вернуло содержимое к описанному.
Сравни с тем, что я мерил в другой теме: повторный запуск docker compose такую же правку НЕ исправляет, потому что он смотрит только на изменения в своём описании. Разница принципиальная - здесь инструмент каждый раз спрашивает реальность о фактическом состоянии ресурсов и сравнивает.
// Практика работы с дрейфом такая. Регулярный прогон плана по расписанию с оповещением, если разница появилась: это ловит и ручные правки, и изменения на стороне облака. Ручные правки в аварию считаются нормальными, но обязаны в тот же день вернуться в описание. А ресурсы, созданные руками, либо удаляют, либо заводят в состояние отдельной командой импорта - иначе следующий план предложит создать дубль.
- дрейф
- расхождение между описанием и реальностью, возникшее мимо инструмента
- импорт ресурса
- занести существующий объект в состояние, чтобы им начали управлять
Разделение состояния
Одно состояние на всю инфраструктуру - типичная ошибка роста. Чем оно больше, тем дольше идёт каждый план (инструмент опрашивает все ресурсы), тем шире радиус поражения ошибки и тем чаще команды мешают друг другу на замке.
Режут обычно по двум осям сразу: по среде (тест, предпрод, прод) и по слою (сеть, кластер, базы, приложения). Чем выше слой, тем чаще его трогают: сеть меняют раз в квартал, приложения - каждый день. Держать их в одном состоянии значит каждый день трогать план, в котором есть сеть.
// Связывают куски через выходные значения одного и чтение их другим. Это же задаёт направление зависимостей: нижние слои ничего не знают о верхних. И полезная привычка: если план идёт дольше пары минут или в нём больше сотни ресурсов - это сигнал резать, а не терпеть.
- радиус поражения
- сколько ресурсов может задеть одна ошибка в применении
- слой инфраструктуры
- группа ресурсов с общей частотой изменений: сеть, кластер, приложения
Как отвечать: «Кто-то поправил ресурс руками в консоли. Что теперь?»
Сначала спокойно: инструмент это заметит. Я проверял на стенде - правка созданного файла руками сразу попала в план как расхождение, а применение вернуло описанное состояние. Это, кстати, важное отличие от простого повторного запуска описания в других инструментах: там такая правка может остаться незамеченной. Дальше по порядку. Если правка была нужной, её переносят в описание в тот же день, иначе следующее применение её снесёт и все удивятся. Если ресурс был создан руками целиком, его либо удаляют, либо заводят в состояние командой импорта, потому что иначе план предложит создать дубль. И на будущее ставлю регулярный прогон плана по расписанию с оповещением о расхождениях: он ловит и ручные правки, и изменения, которые сделало само облако.
Ответ показывает механику обнаружения, разводит два случая (правка и созданный руками ресурс) и добавляет профилактику. Регулярный прогон плана - признак человека, который этим живёт.
На чём валятся
- −Держат состояние локально или в репозитории, а не в общем хранилище с замком.
- −Не знают, что в состоянии лежат секреты открытым текстом, и раздают к нему доступ.
- −Теряют состояние и получают дубли ресурсов при следующем применении.
- −Создают ресурсы руками и не импортируют их в состояние.
- −Держат одно состояние на всё: план идёт десять минут и задевает всё сразу.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 7, остальные разбираются в тренажёре.
- Ночью дежурный руками поднял лимиты у ресурса через консоль облака. Что покажет следующий plan?A)Предложит вернуть параметры к тем, что описаны в кодеB)Оставит ручную правку и подстроит под неё конфигурациюC)Откажется работать, пока изменение не будет импортированоD)Не заметит правку: состояние сравнивается только с кодом
показать ответ и разбор
+A)Предложит вернуть параметры к тем, что описаны в коде// разбор: Terraform считает код источником правды: обновляя данные о ресурсах, он видит расхождение и планирует вернуть всё к описанному. Отсюда правило про ручные правки в проде — они живут до ближайшего применения. Порядок действий после аварийной правки: перенести изменение в код и применить, а не надеяться, что оно приживётся. Отдельная ловушка: часть ручных изменений приводит не к правке, а к пересозданию ресурса.
- Стейт лежит у одного инженера на ноутбуке. Команда растёт. Куда его перенести?A)Закоммитить state в git, чтобы был у всехB)В remote backend с блокировкой (S3+DynamoDB, GCS и т.п.)C)Раздать копию файла каждому в командеD)Хранить на общем сетевом диске без блокировки
показать ответ и разбор
+B)В remote backend с блокировкой (S3+DynamoDB, GCS и т.п.)// разбор: Локальный state не годится для команды: он один, содержит секреты и требует блокировки на время операций. Его переносят в remote backend (S3 с DynamoDB-локом, GCS, Terraform Cloud): состояние общее, шифруется на стороне бэкенда, а лок не даёт двум apply идти одновременно. Коммитить state в git нельзя — там чувствительные данные и нет механизма блокировки.
- Переименовали ресурс/модуль в коде для наведения порядка. План хочет уничтожить старый и создать новый. Как избежать пересоздания?A)Просто применить: terraform сам поймёт, что это переименованиеB)Откатить переименование и просто не рефакторить кодC)terraform state mv (или блок moved) — переклеить адрес в stateD)Удалить ресурс из state и заново импортировать под новым именем
показать ответ и разбор
+C)terraform state mv (или блок moved) — переклеить адрес в state// разбор: Terraform привязывает ресурсы к их адресу в state; сменил адрес (переименовал ресурс/модуль) — для него это удаление старого и создание нового. Чтобы просто «переклеить» адрес без пересоздания: terraform state mv <старый> <новый> или декларативный блок moved {} в конфиге (переживает ревью и применяется всеми). После этого plan покажет отсутствие изменений в инфраструктуре.
- В state лежат пароли и ключи открытым текстом. Как снизить риск?A)Шифровать backend и жёстко ограничить доступ к stateB)Убрать sensitive-переменные, и в state их не будетC)Хранить state в приватном git-репозиторииD)Закодировать значения в base64 внутри state
показать ответ и разбор
+A)Шифровать backend и жёстко ограничить доступ к state// разбор: Terraform пишет в state фактические значения, включая секреты, — открытым текстом (пометка sensitive лишь прячет их в выводе плана). Поэтому state защищают как секрет: шифрование backend at-rest (S3 SSE/KMS), строгий доступ (IAM только тем, кому нужно), не хранить в git, не выводить секреты в outputs. Ещё лучше — не гонять секреты через terraform вовсе, а подтягивать из Vault/секрет-менеджера в рантайме.
- Что хранит файл состояния (state) Terraform?A)Резервную копию настроек облакаB)Историю всех выполненных командC)Связь кода с созданными ресурсамиD)Очередь ресурсов, ожидающих создания
показать ответ и разбор
+C)Связь кода с созданными ресурсами// разбор: Состояние связывает адрес ресурса в коде с его идентификатором в облаке — без него инструмент не отличит «создать заново» от «уже есть». Отсюда и требования: общее хранилище с блокировкой и ограниченный доступ, потому что внутри лежат и секреты.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.