Когда файл состояния Terraform исчезает: стратегии восстановления, которые действительно работают
Вы запускаете terraform plan и вместо привычного вывода получаете ошибку. Файл состояния отсутствует. Или поврежден. Или заблокирован процессом, который умер несколько часов назад. Первая мысль — паниковать, но вот что нужно знать: ваша инфраструктура, скорее всего, все еще работает. Серверы, базы данных и балансировщики нагрузки на месте. Сломалось лишь то, что Terraform считает существующим.
Такая ситуация редка, но когда она случается, команды замирают. Вы не можете вносить изменения через код, пока состояние не восстановлено. Хорошая новость: восстановление возможно, и наличие плана превращает многочасовой кризис в быструю починку.
Почему ломаются файлы состояния
Файлы состояния выходят из строя несколькими предсказуемыми способами. Самый распространенный — случайное удаление. Кто-то чистит S3-бакет и не замечает, что там был файл состояния. Другой сценарий — повреждение из-за прерванной операции записи. Проблемы с сетью, отключение питания или аварийное завершение процесса могут оставить файл состояния наполовину записанным и нечитаемым.
Затем есть проблема блокировки. Terraform блокирует файлы состояния, чтобы предотвратить одновременную запись из нескольких процессов. Если процесс умирает, не сняв блокировку, она остается. Каждый последующий plan или apply завершается ошибкой, потому что Terraform думает, что кто-то еще работает.
Серьезность варьируется, но основная проблема одна: вы потеряли связь между вашим кодом и работающей инфраструктурой.
Первое: не пересобирайте всё
Самое важное правило — удержаться от желания всё снести и начать заново. Ваша инфраструктура все еще работает. Облачный провайдер по-прежнему знает о каждом созданном ресурсе. Потеряна только локальная запись Terraform об этих ресурсах.
Если вы запустите terraform destroy и пересоздадите всё, вы вызовете ненужный даунтайм и рискуете потерять данные. Базы данных будут стерты. Постоянные тома удалены. DNS-записи изменятся. Путь восстановления — в восстановлении состояния, а не в перестройке инфраструктуры.
Восстановление в зависимости от тяжести
Заблокированное состояние: простое исправление
Вот дерево решений, которое поможет быстро определить путь восстановления в зависимости от типа проблемы с файлом состояния:
Если файл состояния существует, но заблокирован, это самый простой сценарий. Выясните, какой процесс удерживает блокировку. Если этот процесс все еще работает, дайте ему завершиться. Если он неожиданно завершился, используйте команду force-unlock:
terraform force-unlock <lock_id>
Но будьте осторожны. Force-unlock безопасен только если вы абсолютно уверены, что никакой другой процесс не пишет в состояние. Если два процесса будут писать одновременно, вы получите поврежденное состояние, которое исправить сложнее, чем простую блокировку.
Удаленное состояние с бэкапом: идеальный сценарий
Если файл состояния был удален, но у вас есть бэкап, вы в хорошей форме. Восстановление тривиально: восстановите бэкап в исходное местоположение.
Вот почему версионирование вашего бэкенда состояния критически важно. Если вы используете S3, включите версионирование бакета. Когда файл удален, вы можете восстановить предыдущую версию прямо из консоли S3 или CLI. Никакого управления файлами бэкапов не требуется.
Если версионирования нет, ручные бэкапы в отдельное место тоже работают. Главное — иметь копию, хранящуюся где-то помимо основного местоположения состояния.
Поврежденное или отсутствующее состояние без бэкапа: сложный путь
Вот где начинается боль. У вас нет бэкапа, и файл состояния либо нечитаем, либо пропал. Но ваша инфраструктура все еще работает. Решение — перестроить состояние, импортируя каждый ресурс по одному.
У Terraform есть команда import, которая читает существующую инфраструктуру и добавляет ее в ваш файл состояния. Для каждого ресурса, определенного в вашем коде, вы запускаете:
Например, чтобы импортировать EC2-инстанс, определенный в вашей конфигурации как aws_instance.web, выполните:
terraform import aws_instance.web i-1234567890abcdef0
Адрес ресурса (aws_instance.web) должен точно совпадать с тем, что у вас в .tf файлах. Если ресурс находится в модуле, используйте путь модуля, например module.my_module.aws_instance.web. После импорта запустите terraform plan, чтобы убедиться, что состояние соответствует вашей конфигурации.
terraform import <resource_type>.<resource_name> <resource_id>
Формат ID ресурса зависит от провайдера. Для AWS это может быть ID инстанса или ARN. Для GCP обычно это имя ресурса или полный URL.
Этот процесс утомителен для крупной инфраструктуры. Если у вас десятки EC2-инстансов, баз RDS, балансировщиков нагрузки и групп безопасности, вы будете запускать команды import довольно долго. Но это единственный способ согласовать ваш код с реальностью, ничего не уничтожая.
Полная потеря без возможности восстановления: ядерный вариант
Иногда состояние потеряно, бэкапов нет, а инфраструктура слишком сложна или плохо документирована, чтобы импортировать ее по частям. В этом случае у вас есть один вариант: пересобрать с нуля.
Это означает уничтожение всех существующих ресурсов и их пересоздание из вашего кода Terraform. Это не то решение, которое принимают легкомысленно, особенно для production-сред. Но если восстановление через импорт невозможно, пересборка часто быстрее, чем попытки вручную восстановить состояние для сотен ресурсов.
Прежде чем идти этим путем, убедитесь, что у вас есть:
- Полный код Terraform, соответствующий тому, что работает
- Бэкапы данных для баз данных и постоянного хранилища
- Окно обслуживания с одобрением заинтересованных сторон
- План отката на случай неудачи пересборки
Практический чеклист для восстановления состояния
Когда состояние ломается, пройдите по этому чеклисту по порядку:
- Подтвердите повреждение — Состояние заблокировано, удалено или повреждено? Внимательно проверьте сообщение об ошибке.
- Проверьте бэкапы — Посмотрите версионирование на вашем бэкенде. Проверьте ручные места хранения бэкапов.
- Восстановите, если возможно — Если у вас есть бэкап, восстановите его и проверьте с помощью
terraform plan. - Force-unlock, если заблокировано — Только если вы уверены, что никакой другой процесс не активен.
- Импортируйте ресурсы — Если бэкапа нет, начните импортировать ресурсы один за другим.
- Рассмотрите пересборку — Только если импорт непрактичен и у вас есть полное покрытие кодом.
Профилактика лучше восстановления
Лучшее время для подготовки к сбою состояния — до того, как он произойдет. Три практики значительно упрощают восстановление:
Во-первых, включите версионирование на вашем бэкенде состояния. Будь то S3, Azure Storage или GCS, версионирование дает вам страховочную сетку от случайного удаления или повреждения.
Во-вторых, автоматизируйте бэкапы. Даже с версионированием храните копии вашего файла состояния в отдельном месте. Простой cron-джоб или шаг пайплайна, который копирует файл состояния в другой бакет или аккаунт хранилища, настраивается за пять минут.
В-третьих, документируйте вашу инфраструктуру. Когда вам нужно импортировать ресурсы, вы должны знать, что существует и какие у них ID. Актуальная инвентаризация ресурсов, либо в README, либо сгенерированная из API вашего облачного провайдера, экономит часы во время восстановления.
Что дальше
Как только состояние восстановлено и вы снова можете запускать terraform plan, работа не закончена. Инцидент должен вызвать пересмотр того, как управляется ваше состояние. Есть ли пробелы в стратегии бэкапов? Стоит ли добавить больше контроля доступа для предотвращения случайного удаления? Нужен ли вам runbook для восстановления состояния?
Восстановление состояния — это не про избегание ошибок. Это про наличие плана на случай, когда ошибки случаются. Команды, которые готовятся к сбою состояния, восстанавливаются за минуты. Команды, которые не готовятся, тратят часы на панику, а затем дни на ручное восстановление того, что потеряли.
Инфраструктура, которую вы построили, все еще здесь. Состояние — это просто карта. Когда карта потеряна, вы не сжигаете город. Вы рисуете новую карту.