← Infrastructure as Code
11 мин · средне · Урок 5 из 5

Удалённый state и блокировки

Почему локальный state ломает командную работу, как вынести его в общий бэкенд и зачем нужны блокировки.

Напоминание про state

Из урока про основы Terraform: state это файл, в котором Terraform помнит, что он уже создал. По нему он понимает, что менять, а что трогать не надо. По умолчанию state лежит локально, в файле terraform.tfstate рядом с кодом. Для одного человека это работает, для команды ломается.

Почему локальный state не годится команде

Локальный state создаёт сразу несколько проблем:

Поэтому state выносят из локальной папки в общее хранилище.

Remote backend

Remote backend хранит state в общем месте, к которому ходят все. Чаще всего это S3-совместимый бакет, HCP Terraform (так с октября 2023 называется бывший Terraform Cloud) или аналог в облаке.

terraform {
  backend "s3" {
    bucket       = "company-tfstate"
    key          = "prod/terraform.tfstate"
    region       = "ru-central1"
    encrypt      = true
    use_lockfile = true
  }
}

Теперь state один на всех, лежит в бакете (часто зашифрованным), а не в репозитории и не на чьём-то ноутбуке. Каждый apply читает и пишет общий state, поэтому все видят одну картину реальности.

Блокировка state

Общий state решает расхождение, но не одновременный запуск: двое всё ещё могут запустить apply разом. Для этого backend поддерживает блокировку (lock). Перед изменением Terraform ставит блокировку на state, и второй запуск ждёт или получает отказ.

$ terraform apply
Acquiring state lock...
Error: state is locked by alice@laptop since 14:02

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

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

Раньше для блокировки поднимали отдельную таблицу в DynamoDB и прописывали её в dynamodb_table. Морока: лишний AWS-сервис ради одного мьютекса, а на S3-совместимых хранилищах вроде Yandex Object Storage или MinIO его просто нет.

Начиная с Terraform 1.10 (и OpenTofu 1.11) блокировка живёт прямо в бакете: рядом со state кладётся lock-файл. Включается строкой use_lockfile = true из примера выше, ничего дополнительно разворачивать не нужно.

Что важно запомнить

Локальный state ломает командную работу: у каждого своя копия, в ней секреты, и двое могут применить разом. Поэтому state выносят в remote backend (S3-совместимый бакет, HCP Terraform), где он один на всех и зашифрован.

Блокировка state не даёт двум apply идти одновременно: первый ставит lock, второй ждёт. Так инфраструктуру в каждый момент меняет только один.

В S3-бэкенде блокировку надо включить руками: use_lockfile = true. До Terraform 1.10 / OpenTofu 1.11 для этого требовалась отдельная таблица DynamoDB, теперь хватает lock-файла в самом бакете.

Этим закрывается трек iac-basics: идея IaC, Terraform, GitOps, модули и удалённый state.

Прошли материал до конца? Отметьте урок пройденным.