Что такое state и зачем он нужен

State (состояние) — это карта, связывающая ваш код с реальными ресурсами в облаке. Без неё Terraform не знал бы, какой сервер в коде соответствует какому серверу в AWS.

State — самый важный и самый опасный артефакт Terraform. Потеряете его — Terraform «забудет» всю инфраструктуру и попробует создать её заново. Сломаете — устроите хаос. Относитесь к нему как к проду.

Terraform управляет тремя мирами: код (что вы хотите, желаемое состояние), реальность (что есть в облаке) и state (что Terraform думает о реальности). State — это связующее звено: он хранит соответствие aws_instance.webi-0abc123. Без него Terraform не отличит свой сервер от чужого.

Что внутри tfstate

Файл terraform.tfstate — это JSON. В нём для каждого ресурса записан его адрес, тип, провайдер и снимок всех атрибутов:

{
  "version": 4,
  "resources": [
    {
      "type": "aws_instance",
      "name": "web",
      "instances": [
        {
          "attributes": {
            "id": "i-0abc123",
            "instance_type": "t2.micro",
            "public_ip": "54.1.2.3"
          }
        }
      ]
    }
  ]
}
   КОД (.tf)          STATE (карта)        РЕАЛЬНОСТЬ (облако)
  желаемое            что знает TF          что есть на самом деле
 -----------        --------------        --------------------
 aws_instance.web -> i-0abc123        ->   [сервер i-0abc123]
 aws_s3.data      -> bucket-xyz       ->   [бакет bucket-xyz]

  plan = сравнить КОД и STATE+РЕАЛЬНОСТЬ, выдать diff

Как работает под капотом

На plan Terraform делает три шага: читает желаемое (код), читает запомненное (state), опрашивает реальность (refresh) и сравнивает. State нужен в том числе чтобы понять, какие ресурсы удалить — их нет в коде, но они есть в state. Смоделируем роль state как «памяти»:

desired = {"web", "db", "cache"}        # в коде
state   = {"web", "db", "old_lb"}       # TF помнит это

to_create = desired - state    # есть в коде, нет в памяти
to_delete = state - desired    # есть в памяти, нет в коде
to_keep   = desired & state    # есть в обоих

print("создать:", to_create)
print("удалить:", to_delete, "<- без state TF бы это НЕ нашёл!")
print("оставить:", to_keep)

«Попробуй сам ▶» — обратите внимание: old_lb попадает в «удалить» только потому, что Terraform помнит его в state. Без state он бы остался брошенным навсегда.

Частые ошибки

  • Коммитить tfstate в git. В нём лежат секреты открытым текстом (пароли, ключи) — прямая утечка.
  • Удалить или потерять state. Terraform забудет инфраструктуру и попытается создать дубли.
  • Редактировать tfstate руками. Один неверный символ — и весь файл невалиден.

Best practices

  • Никогда не храните state в git. Только удалённый бэкенд (об этом — следующий урок).
  • Делайте бэкапы state и включайте версионирование хранилища.
  • Не правьте state текстовым редактором — для этого есть команды terraform state.

Разбор глубже

Возникает резонный вопрос: зачем вообще нужен state, почему Terraform не может каждый раз заново опрашивать облако и сравнивать с кодом? Причин несколько. Во-первых, производительность: полный обход всех ресурсов через API на большом проекте занимал бы минуты и упирался в лимиты. State служит кешем. Во-вторых, сопоставление: облако не знает, что инстанс i-0abc — это именно ваш aws_instance.web; эту привязку хранит только state. В-третьих, удаление: чтобы понять, что ресурс надо снести, Terraform должен помнить, что когда-то его создавал, — без state удалённый из кода ресурс просто остался бы брошенным навсегда.

В state хранятся и метаданные, невидимые в коде: версия формата (version), серийный номер (увеличивается с каждым изменением и помогает обнаружить устаревшую копию), и зависимости между ресурсами на момент последнего apply. Поэтому редактировать state руками крайне опасно — легко рассогласовать эти служебные поля. Для любых правок существуют специальные команды terraform state, которые меняют файл корректно и согласованно. А золотое правило безопасности простое: state — это прод, относитесь к нему так же бережно, как к боевой базе данных.

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

Итог: state — карта между кодом и реальностью, без которой Terraform слеп. Это JSON с секретами, поэтому его берегут и не кладут в git. Дальше — где его правильно хранить.

Проверьте себя
1. Зачем Terraform нужен state-файл?
AДля ускорения apply
BЧтобы знать соответствие между ресурсами в коде и реальными объектами в облаке
CДля хранения провайдеров
DЭто просто лог операций
2. Почему нельзя коммитить terraform.tfstate в git?
AФайл слишком большой
BВ нём хранятся секреты (пароли, ключи) открытым текстом
CGit его повреждает
DЭто запрещено лицензией