linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
Intro
Lessons
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Уроки
  • How it works
  • База знаний
  • Шпаргалка
  • Capstone
  • Собеседование
Cluster

← все кластеры

State, backend, lock, drift

Самая частая тема на Terraform-собесе. State - то, чем Terraform отличается от kubectl apply. Что в нём лежит, зачем lock, как ловить drift, когда допустима state surgery. Вопросы из реальных DevOps-собесов: AWS-команды, банки, средние российские инфра-команды.

7 вопросов · ~28 мин чтения

Questions

На этой странице

  1. 01Зачем Terraform нужен state? Почему нельзя просто читать API провайдера?
  2. 02Зачем remote backend и что такое state lock? Что будет без lock?
  3. 03Зачем `terraform import` и в чём его боль?
  4. 04Что такое drift и как его ловить в проде?
  5. 05Чем `terraform taint` отличается от `-replace`? Почему taint deprecated?
  6. 06Sensitive в state - что не так и как защититься?
  7. 07`terraform state mv` и `rm` - когда допустимо, когда опасно?

#what-is-state-and-why

juniorчасто

Зачем Terraform нужен state? Почему нельзя просто читать API провайдера?

Что отвечать

State - карта между HCL и реальными ресурсами провайдера. В нём id'шники ресурсов, computed-атрибуты, метаданные. Без state Terraform не знает, какой `aws_s3_bucket.demo` в HCL соответствует какому реальному bucket - имена в HCL это адреса, а не глобальные идентификаторы. Читать API каждый раз - дорого и иногда невозможно (data lag, eventual consistency), плюс это не покрывает «удалили из HCL - надо удалить ресурс».

Что хотят услышать

Senior должен: - объяснить адресацию: `aws_s3_bucket.demo` это адрес в графе, реальный id (например `arn:aws:s3:::my-bucket-12345`) хранится в state - назвать что state нужен для трёх вещей: маппинг HCL→реальные id, кэш computed-атрибутов, понимание «было/стало» для diff в plan - сказать что без state каждый plan был бы full-refresh, и для десятков тысяч ресурсов это бессмысленно по времени - упомянуть `terraform refresh` как форсированный re-read из API, обычно не нужен (apply сам делает refresh)

Подводные камни

  • ✗ Сказать что state - это «бэкап конфига». Конфиг - это HCL, state - маппинг
  • ✗ Думать что state можно восстановить из API. Частично - да, через import, но computed-атрибуты вроде random_id это не вернёт
  • ✗ Не упомянуть зачем нужны computed-атрибуты в state - тогда непонятно, откуда там pasword'ы (sensitive в state)

Follow-up

  • ? Что произойдёт если удалить state-файл? Какие данные восстановимы?
  • ? Чем `terraform refresh` отличается от `terraform plan -refresh-only`?
  • ? Зачем там computed-атрибуты, если их в HCL не было?

Глубина в базе знаний

  • State: память Terraform о созданном
  • terraform plan: посмотреть, что Terraform собирается сделать
  • Импорт: захват существующего ресурса под Terraform
tags: state, fundamentals

#remote-backend-why-and-lock

intermediateчасто

Зачем remote backend и что такое state lock? Что будет без lock?

Что отвечать

Local state не работает в команде - двое разработчиков накатят несинхронизированные изменения и сломают друг другу state. Remote backend (S3+DynamoDB, GCS, Azure Blob, Terraform Cloud) решает две задачи: shared storage и lock. Lock - exclusive mutex на время plan/apply. Без lock два apply одновременно создадут гонку: оба прочтут state, оба применят, последний запишет - часть ресурсов исчезнет из state и станет orphan'ами в провайдере.

Что хотят услышать

Senior должен: - различить storage (S3) и lock (DynamoDB в AWS-стеке). S3 сам по себе lock не даёт - нужен внешний механизм - назвать что lock берётся на старте plan/apply и держится до конца. `-lock-timeout=10m` спасает в CI когда чей-то apply завис - сказать про `terraform force-unlock <id>` и когда это безопасно (только если уверен что державший процесс умер) - упомянуть что Terraform Cloud / TFE снимает нагрузку lock+storage в один сервис, плюс audit log - назвать риск: state в S3 без шифрования = pasword'ы в открытом виде. Минимум - SSE, лучше KMS+IAM bucket policy

Подводные камни

  • ✗ Сказать что DynamoDB хранит state. Нет, только lock - state в S3
  • ✗ Force-unlock «на всякий случай» когда apply кажется висящим - часто apply жив, force-unlock даст ему писать в состояние без lock
  • ✗ Включить S3 versioning «на всякий» и забыть про lifecycle - расходы растут вместе с числом apply

Follow-up

  • ? Что делает `terraform force-unlock` под капотом?
  • ? Чем отличается lock в S3+DynamoDB от lock в Terraform Cloud?
  • ? Можно ли использовать только S3 без DynamoDB для одиночной разработки?

Глубина в базе знаний

  • Remote state в S3: бакет, DynamoDB lock, encryption
  • Backend в Terraform: где живёт state
  • .terraform.lock.hcl: фиксация версий провайдеров
  • Секреты и Terraform state: где хранить и как читать
tags: state, backend, lock, cicdbook: mastering.terraform.epub:ch7

#terraform-import-when-and-pitfalls

intermediateчасто

Зачем `terraform import` и в чём его боль?

Что отвечать

Import «всыновляет» уже существующий ресурс в state, не создавая его заново. Используется когда ресурс был создан руками (или другим инструментом), а ты хочешь начать управлять им через Terraform. Боль: import создаёт запись в state, но HCL ты пишешь сам, на глаз. Если HCL не совпадает с реальностью - следующий plan покажет drift и попытается «починить» ресурс под HCL. На сложных ресурсах (security groups, IAM-политики) повторить структуру руками - часы работы. С 1.5 появился `import {}` блок - декларативный, можно коммитить в репо.

Что хотят услышать

Senior должен: - различить CLI `terraform import` (мутирует state, без планирования) и блок `import {}` (через plan, можно ревьюить в PR) - назвать классический workflow: `import`, потом `terraform plan`, потом дописать HCL пока plan не станет no-op - упомянуть `terraform plan -generate-config-out=imported.tf` - генератор HCL из реального ресурса, в 1.5+. Качество HCL так-себе (нет local'ов, нет for_each), но скелет даёт - назвать что import не работает для child-модулей напрямую, для них нужен полный путь `module.foo.aws_s3_bucket.demo`

Подводные камни

  • ✗ Думать что import «перенесёт» ресурс. Он только привяжет state к существующему - сам ресурс не трогается
  • ✗ Импортнуть в state и забыть написать HCL. На следующем apply Terraform увидит «ресурс есть в state, но не в HCL» и удалит
  • ✗ Импортить много ресурсов в один заход через скрипт - один сбой, и state в неконсистентном состоянии. Импортируй по одному с коммитом после каждого

Follow-up

  • ? Чем `import {}` блок принципиально лучше CLI-команды?
  • ? Что делает `-generate-config-out` и почему его выхлоп нельзя коммитить как есть?
  • ? Как импортнуть ресурс в child-модуль? Какой адрес писать?

Глубина в базе знаний

  • Импорт: захват существующего ресурса под Terraform
  • terraform plan: посмотреть, что Terraform собирается сделать
  • State: память Terraform о созданном
tags: state, import, refactorbook: Packt.Terraform.Cookbook.pdf:ch3

#drift-detection-how-to-catch

intermediateчасто

Что такое drift и как его ловить в проде?

Что отвечать

Drift - расхождение между state и реальным состоянием в провайдере. Кто-то зашёл в AWS Console и поменял тег вручную, security group обновился через другой инструмент, IAM-роль откатили из incident response. Поймать: `terraform plan -refresh-only` или просто `terraform plan` - покажет diff. В CI крутить cron-job: `plan -detailed-exitcode`, exit 2 значит есть изменения, шлёшь алерт в Slack. Решение по факту: либо принять drift через apply, либо вернуть ресурс к state-у через apply обратно.

Что хотят услышать

Senior должен: - назвать `-detailed-exitcode`: 0 = no changes, 2 = changes, 1 = error. Это базовый кирпич для cron-detection - различить «хороший drift» (кто-то починил инцидент быстрее IaC) и «плохой» (кто-то нарушил GitOps-процесс). Алерт нужен на оба, реакция разная - упомянуть что drift в cloud-init / user_data / Lambda code чаще всего нормален: реальный конфиг живёт в другом месте, IaC только bootstrap'ит - назвать `ignore_changes` как штатный способ исключить шумные атрибуты вроде `tags.LastModified` из drift-detection

Подводные камни

  • ✗ Бегать `plan` в CI без `-detailed-exitcode` и парсить stdout regex'ом - сломается на каждом обновлении terraform
  • ✗ Считать каждый drift инцидентом - на больших инфрах постоянный шум от cloud-managed-атрибутов (auto-scaling adjustments)
  • ✗ Чинить drift через ручной `apply` каждый раз - постепенно расходишься с PR-процессом, теряешь review

Follow-up

  • ? Что значит exit code 2 у `terraform plan` и зачем он нужен?
  • ? Как настроить `ignore_changes` чтобы не реагировать на ASG capacity?
  • ? Что лучше для drift-detection: cron в CI или Terraform Cloud drift detection?

Глубина в базе знаний

  • [[tf-drift-detection]]
  • Plan-as-artifact и automation mode в CI
  • terraform plan: посмотреть, что Terraform собирается сделать
  • lifecycle: управляем поведением resource
tags: state, drift, cicd

#taint-vs-replace

intermediateиногда

Чем `terraform taint` отличается от `-replace`? Почему taint deprecated?

Что отвечать

`terraform taint` помечал ресурс в state как «требует пересоздания», и следующий apply его пересобирал. Проблема: taint мутировал state немедленно, без планирования. Если коллега уже сделал plan и собирался apply'ить - его plan был неактуален. С Terraform 0.15 появился `terraform apply -replace=<address>`: то же поведение, но через plan, то есть видно в diff, обсуждается в PR, проходит CI-review. Taint оставлен для обратной совместимости, но в новых проектах не используют.

Что хотят услышать

Кандидат должен: - сказать что `-replace` - правильный современный путь, taint - legacy - объяснить семантику: ресурс destroy'ится и create'ится с тем же адресом, новый id появляется в state - упомянуть `create_before_destroy` lifecycle и как это меняет порядок replace для zero-downtime - назвать кейс: replace полезен когда HCL не изменился, но ресурс корраптнулся (DB instance в FAILED state, EC2 unhealthy, конфиг дрейфовал)

Подводные камни

  • ✗ Использовать taint в pipeline. На каждом запуске мутирует state - коллеги ловят неожиданные изменения
  • ✗ Сказать что replace меняет id - id меняется только если ресурс действительно пересоздаётся (новый ARN, новый EC2)
  • ✗ Применить replace к ресурсу с `prevent_destroy = true` и удивляться что план падает - lifecycle защита приоритетнее

Follow-up

  • ? Что происходит с зависимыми ресурсами при `-replace`?
  • ? Можно ли replace data source? Почему нет?
  • ? В каких сценариях `-replace` лучше чем `destroy` + `apply`?

Глубина в базе знаний

  • -replace и -target: точечные операции с одним ресурсом
  • lifecycle: управляем поведением resource
  • terraform apply: применить план в реальном облаке
tags: state, lifecycle

#state-secrets-and-risks

seniorиногда

Sensitive в state - что не так и как защититься?

Что отвечать

State пишет в plain JSON любые атрибуты, включая password'ы, ключи, secrets. `sensitive = true` на output только прячет значение из CLI, в state оно всё равно лежит как есть. Защита - на уровне backend: S3 с KMS-шифрованием, IAM bucket policy с принципом least privilege, access log на bucket. И главное: не клади plain secrets в HCL - читай из Vault/SSM/Secrets Manager через data source, тогда secret хотя бы не идёт в git, хоть и оседает в state.

Что хотят услышать

Senior должен: - чётко сказать что `sensitive = true` это только UI-фильтр, не encryption. State - не место для секретов, но они там неизбежно оседают - назвать KMS + IAM + access logs как минимальную трёхслойную защиту - упомянуть что Terraform Cloud / TFE шифрует state в покое автоматически, плюс audit log кто читал - назвать решение для credential rotation: rotate в secrets-store, потом apply пересоздаст ресурс с новым значением. State будет содержать новое значение, старое нигде не остаётся (если versioning включён - остаётся в старых версиях, не забыть про lifecycle)

Подводные камни

  • ✗ Сказать что `sensitive = true` шифрует - нет, только маскирует
  • ✗ Положить ключ в .tfvars и закоммитить - state будет содержать, но и git-история тоже
  • ✗ Не настроить bucket policy и оставить state публично читаемым через S3 - класс утечки, известный по нескольким реальным инцидентам

Follow-up

  • ? Что делает `terraform output -raw <name>` с sensitive значением?
  • ? Чем подход «secret через data source» лучше чем `sensitive` на variable?
  • ? Как настроить IAM bucket policy для state-bucket'а с минимальными правами для CI?

Глубина в базе знаний

  • Секреты и Terraform state: где хранить и как читать
  • sensitive в Terraform: про логи, не про шифрование
  • Remote state в S3: бакет, DynamoDB lock, encryption
tags: state, security, secretsbook: terraform.in.depth.pdf:ch9

#state-surgery-mv-rm-when-ok

seniorиногда

`terraform state mv` и `rm` - когда допустимо, когда опасно?

Что отвечать

State surgery нужна при рефакторинге: переименовал ресурс в HCL, вынес в модуль, разделил большой root на несколько. Без `state mv` Terraform увидит «старого нет, нового нет в state» и захочет destroy+create. Опасность: `state rm` отвязывает ресурс от state, но в провайдере он остаётся. Если забыть про него - получаешь orphan. С 1.1 `moved {}` блок заменяет `state mv` в большинстве случаев: декларативный, ревьюится в PR, не мутирует state до apply.

Что хотят услышать

Senior должен: - сказать что `moved {}` блок предпочтительнее `state mv` для переименований и переездов между модулями - см. ADR-логика «через plan, не через мутацию» - назвать когда `state rm` оправдан: ресурс передан другой команде / другому root-модулю, и его state-запись там уже есть. Без `rm` получишь два владельца одного ресурса - упомянуть `terraform state replace-provider` - редкая, но нужная операция при смене источника провайдера (registry.terraform.io → registry.opentofu.org) - назвать что после любой surgery первый `plan` обязан быть no-op. Если показывает diff - твой `mv` был неточный, undo и думай дальше

Подводные камни

  • ✗ Сделать `state rm` без удаления ресурса в провайдере - orphan, за который никто не платит вниманием, но AWS платит деньгами
  • ✗ Использовать `state mv` вместо `moved {}` в team-настройке - коллега видит твой stale plan, ругается
  • ✗ Делать surgery без бэкапа state. `terraform state pull > state.backup.json` перед любой `mv/rm` - правило

Follow-up

  • ? Чем `moved {}` блок принципиально надёжнее `terraform state mv`?
  • ? Когда `state rm` нужен, и `removed {}` блок его не заменит?
  • ? Как откатить неудачный `state mv`? Что положить в .backup?

Глубина в базе знаний

  • state mv, state rm, state pull/push: ручные операции
  • moved блок: переименование без destroy
  • [[tf-removed-block]]
  • Паттерны рефакторинга: count→for_each, split files, extract module
tags: state, refactor, surgerybook: mastering.terraform.epub:ch12
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки