Удалённый state и блокировки
Почему локальный state ломает командную работу, как вынести его в общий бэкенд и зачем нужны блокировки.
Напоминание про state
Из урока про основы Terraform: state это файл, в котором Terraform
помнит, что он уже создал. По нему он понимает, что менять, а что трогать
не надо. По умолчанию state лежит локально, в файле terraform.tfstate
рядом с кодом. Для одного человека это работает, для команды ломается.
Почему локальный state не годится команде
Локальный state создаёт сразу несколько проблем:
- Расхождение. У каждого свой файл state. Двое применили изменения, и их представления о реальности разошлись: Terraform у одного не знает про ресурсы, созданные другим.
- Секреты в git. В state лежат значения в открытом виде (пароли, ключи). Закоммитить его в репозиторий означает утечку, а не закоммитить означает, что у других его нет.
- Одновременное применение. Двое запустили
applyразом и перетёрли работу друг друга, оставив инфраструктуру в непонятном состоянии.
Поэтому 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.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс