Когда состояние инфраструктуры не соответствует реальности

Вы настроили инфраструктуру как код. Terraform, Pulumi или любой другой инструмент. Всё отслеживается, версионируется и воспроизводится. Ваш state-файл говорит, что на production-сервере 4 CPU и 16 ГБ RAM. Жизнь прекрасна.

Но однажды кто-то заходит в облачную консоль и вручную меняет размер этого сервера. Возможно, возникла проблема с производительностью, и команда поддержки должна была действовать быстро. Возможно, кто-то запустил скрипт, которого нет в вашем коде. Какова бы ни была причина, ваш state-файл по-прежнему показывает 4 CPU и 16 ГБ, но реальный сервер теперь работает с 8 CPU и 32 ГБ.

Это расхождение между тем, что говорит ваш state, и тем, что существует на самом деле, называется дрифтом (drift). И это гораздо более серьёзная проблема, чем думает большинство команд.

Почему возникает дрифт

Дрифт — не редкость. Он случается чаще, чем вы думаете, и обычно по понятным причинам:

  • Кто-то вносит быстрое изменение в облачной консоли во время инцидента
  • Другая команда запускает свою автоматизацию, которая затрагивает ваши ресурсы
  • Инструмент мониторинга автоматически масштабирует что-то без обновления state
  • Разработчик напрямую изменяет ресурс для тестирования и забывает откатить

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

Реальная цена дрифта

Дрифт не просто ломает вашу автоматизацию. Он подрывает доверие ко всему процессу доставки. Когда ваша команда не может доверять тому, что инфраструктура как код отражает реальность, они снова начинают вносить ручные изменения. А ручные изменения ведут к ещё большему дрифту. Это нисходящая спираль.

Для production-сред дрифт особенно опасен. Ресурс, изменённый вне вашего процесса, может вести себя иначе под нагрузкой. Группы безопасности, изменённые вручную, могут оставить бреши. Экземпляры баз данных, размер которых был изменён без обновления state, могут вызвать неожиданные расходы или проблемы с производительностью. А когда что-то идёт не так, у вас нет надёжной записи о том, что на самом деле изменилось.

Обнаружение дрифта: простой способ

Самый базовый подход к обнаружению дрифта — ручное сравнение. В Terraform запуск terraform plan показывает разницу между вашим кодом, вашим state и фактической инфраструктурой. Любой ресурс, изменённый вне вашего кода, отобразится как неожиданная модификация.

Вот команда для запуска и на что обращать внимание:

# Запуск terraform plan без изменений кода для обнаружения дрифта
terraform plan

# Пример вывода, показывающего дрифт (изменения кода не вносились)
# Terraform will perform the following actions:
#
#   # aws_instance.web_server will be updated in-place
#   ~ resource "aws_instance" "web_server" {
#       ~ instance_type = "t3.large" -> "t3.medium"
#         id            = "i-0abcd1234efgh5678"
#         tags          = {}
#         # (12 unchanged attributes hidden)
#     }
#
# Plan: 0 to add, 1 to change, 0 to destroy.

# Любые изменения, отображаемые при отсутствии модификаций кода = дрифт

Это работает для периодических проверок. Но у ручного обнаружения есть фундаментальная проблема: вы находите дрифт только когда ищете его. Если вы проверяете раз в неделю, дрифт может существовать днями, прежде чем вы заметите. А за это время он может вызвать реальные проблемы.

Автоматизация обнаружения дрифта

Для сред, требующих постоянного контроля, обнаружение дрифта должно работать автоматически. Многие команды настраивают запланированные пайплайны, которые регулярно запускают terraform plan или эквивалентные команды. Когда дрифт обнаружен, пайплайн отправляет уведомление команде.

Некоторые инструменты имеют встроенную поддержку. Terraform Cloud и Atlantis предлагают автоматическое обнаружение дрифта. У Pulumi есть аналогичные возможности. Но даже без этих инструментов вы можете настроить простой cron job или запланированный CI-пайплайн, который запускает валидацию инфраструктуры и оповещает о несоответствиях.

Автоматизированное обнаружение особенно важно для production-сред. Дрифт в production не ждёт вашей еженедельной проверки. Он влияет на пользователей немедленно.

Что делать, когда вы нашли дрифт

Обнаружение — только половина проблемы. Как только вы знаете, что дрифт существует, нужно решить, что с ним делать. У вас есть два основных варианта:

Следующая блок-схема суммирует два основных пути обработки дрифта:

flowchart TD A[Дрифт обнаружен] --> B{Изменение было намеренным?} B -->|Нет| C[Привести к коду] B -->|Да| D{Должно ли это стать новым стандартом?} D -->|Нет| C D -->|Да| E[Обновить state в соответствии с реальностью] C --> F[Запустить apply для восстановления желаемого состояния] E --> G[Импортировать ресурс и обновить код] F --> H[Проверить отсутствие остаточного дрифта] G --> H H --> I[Документировать изменение]

Вариант 1: Привести инфраструктуру обратно к вашему коду. Запустите вашу конфигурацию снова, чтобы вернуть инфраструктуру в желаемое состояние. Это самый безопасный выбор для production-сред. Он подкрепляет идею, что ваш код является источником истины, и ручные изменения не сохранятся.

Вариант 2: Обновить ваш state в соответствии с реальностью. Импортируйте текущую инфраструктуру в ваш state, затем обновите код, чтобы он соответствовал. Это имеет смысл, когда ручное изменение было намеренным и должно стать новым стандартом. Но будьте осторожны: принятие дрифта в ваш state означает, что вы соглашаетесь с тем, что инфраструктура может быть изменена вне вашего определённого процесса.

Большинство зрелых команд выбирают первый вариант для production. Они приводят инфраструктуру обратно к желаемому состоянию. Эта практика называется реконсилиацией (reconciliation), и это основная идея таких инструментов, как Kubernetes operators и GitOps-процессы. Система непрерывно проверяет, соответствует ли реальность желаемому состоянию, и автоматически исправляет любой обнаруженный дрифт.

Построение практики обнаружения дрифта

Если вы настраиваете обнаружение дрифта впервые, начните с простого. Запустите запланированный plan для ваших самых критичных сред. Отправляйте результаты в чат-канал, где команда может их видеть. Сделайте дрифт видимым, прежде чем пытаться автоматизировать реакцию.

Как только команда привыкнет видеть уведомления о дрифте, начните автоматизировать реакцию для сред, отличных от production. Пусть пайплайн автоматически реконсилирует staging и development-среды. Для production оставьте человека в цикле, пока вы не будете уверены в своей автоматизации.

И всегда помните: обнаружение дрифта — это не только поиск ошибок. Это поддержание доверия к вашей инфраструктуре как коду. Когда ваша команда знает, что state точен, они могут вносить изменения с уверенностью. Когда нет — всё замедляется.

Практический чеклист

  • Запускайте terraform plan или эквивалент по расписанию для production-сред
  • Отправляйте уведомления о дрифте в командный канал
  • Определите чёткую политику: приводить к коду или обновлять state
  • Автоматизируйте реконсилиацию сначала для сред, отличных от production
  • Документируйте, как обрабатывать намеренные ручные изменения
  • Ежемесячно анализируйте паттерны дрифта для выявления пробелов в процессах

Вывод

Дрифт — это не сбой ваших инструментов. Это сигнал о том, что в вашем процессе есть пробел. Кому-то нужно было внести изменение, и определённый процесс им не подошёл. Возможно, он был слишком медленным. Возможно, у них не было доступа. Возможно, они не знали, что процесс существует.

Когда вы находите дрифт, не просто исправляйте инфраструктуру. Исправьте процесс, который позволил дрифту возникнуть. Сделайте так, чтобы людям было проще вносить изменения через правильный путь, чем в обход него. Вот как вы строите систему, которая остаётся согласованной без постоянного контроля.