Когда инфраструктура расходится с кодом: как решить — исправить или принять
Вы открываете дашборд инфраструктуры в понедельник утром. На первый взгляд всё выглядит нормально. Потом замечаете: размер инстанса базы данных отличается от того, что указано в вашем Terraform-коде. Кто-то изменил его через облачную консоль на выходных. Пайплайн не запускался. Код говорит одно, а реальная инфраструктура — другое.
Это дрифт. Он случается чаще, чем большинство команд готовы признать. Кто-то вносит ручное изменение во время инцидента. Провайдер облачных услуг автоматически обновляет свойство ресурса. Коллега правит правило группы безопасности напрямую, потому что нужно было сделать быстро. Какова бы ни была причина, теперь у вас есть разрыв между тем, что декларирует код, и тем, что на самом деле существует в инфраструктуре.
Вопрос не в том, произойдёт ли дрифт. Он произойдёт. Настоящий вопрос — что вы будете делать после его обнаружения.
Три пути к примирению
Примирение — это процесс возврата инфраструктуры в соответствие с определениями кода. Но единого правильного способа не существует. Лучший подход зависит от ситуации, уровня риска и контекста изменения.
Используйте это дерево решений, чтобы быстро определить подходящий путь:
Путь первый: перезапустить пайплайн
Самый простой вариант — снова запустить пайплайн, не меняя код. Вы берёте существующий Infrastructure as Code (IaC), оставляете его без изменений и выполняете шаг apply. Инструменты вроде Terraform, Pulumi или AWS CloudFormation сравнят файл состояния с реальными ресурсами и внесут необходимые корректировки, чтобы вернуть всё к тому, что определено в коде.
Это хорошо работает, когда дрифт произошёл случайно. Кто-то изменил размер инстанса через консоль, не осознавая, что обходит пайплайн. Разработчик временно открыл порт в группе безопасности для отладки и забыл его закрыть. Плановое задание другой команды изменило тег на ваших ресурсах. В таких случаях перезапуск пайплайна — чистое и безопасное решение. Код представляет желаемое состояние, и инфраструктуре нужно просто догнать его.
Риск здесь низкий, потому что изменения не были намеренными. Вы исправляете ошибку, а не отменяете осознанное решение.
Путь второй: принять дрифт
Иногда ручное изменение было на самом деле правильным. Во время производственного инцидента ваша операционная команда увеличила базу данных, чтобы справиться со скачком трафика. Приложение осталось работать благодаря этому изменению. После инцидента вы понимаете, что новая мощность больше подходит для текущей нагрузки. Старое значение в коде теперь устарело.
В этом случае откат к старому коду был бы ошибкой. Вы отменили бы исправление, которое сохранило работоспособность системы. Вместо этого вы обновляете IaC, чтобы отразить новое состояние. Это называется принятием дрифта. Вы меняете код в соответствии с тем, что реально работает, а затем запускаете пайплайн, чтобы подтвердить согласованность.
Принятие дрифта сохраняет пайплайн как единый источник истины, одновременно сохраняя изменения, которые оказались полезными. Но это требует тщательной оценки. Нужно понять, почему было сделано изменение, было ли оно протестировано и не вызывает ли оно побочных эффектов. Принятие дрифта без проверки может превратить ваш IaC в беспорядочный набор недокументированных решений.
Путь третий: ручное восстановление
Бывают ситуации, когда запускать автоматизированный пайплайн слишком рискованно. Ресурс с дрифтом обслуживает живой трафик. Изменение группы безопасности защищает критическую конечную точку. Конфигурация балансировщика нагрузки распределяет запросы между инстансами. Если ваш пайплайн применит изменения автоматически, это может вызвать кратковременное прерывание или даже полный сбой.
В таких случаях ручное восстановление — более безопасный выбор. Кто-то с доступом к облачной консоли или серверу изучает изменения по одному, аккуратно откатывает их и отслеживает влияние в реальном времени. Это медленнее и требует больше труда, но даёт контроль над порядком и временем каждого изменения.
Ручное восстановление — не признак неудачи автоматизации. Это признание того, что некоторые ресурсы требуют человеческого суждения при восстановлении. Ключевой момент — задокументировать, что было сделано и почему, чтобы в следующий раз, когда появится такой же дрифт, вы могли решить, стоит ли автоматизировать исправление.
Кто должен принимать решение?
Примирение — это не чисто техническое решение. Оно требует контекста. Был ли дрифт вызван ошибкой, инцидентом или экспериментом, который никогда не был зафиксирован? Ответ определяет, какой путь выбрать.
Решение должны принимать люди, понимающие изменение и его влияние. Это может быть операционная команда, которая обрабатывала инцидент, разработчик, сделавший ручное исправление, или платформенный инженер, отслеживающий поведение системы. Один человек, принимающий решение изолированно, легко может неправильно оценить ситуацию.
Простое эмпирическое правило: если вы не знаете, почему произошёл дрифт, не выполняйте примирение автоматически. Сначала расследуйте. Перезапускайте пайплайн только когда уверены, что изменение было непреднамеренным. Принимайте дрифт только когда уверены, что изменение было полезным. Восстанавливайте вручную, когда не уверены ни в том, ни в другом.
Практический чеклист для решений о примирении
Прежде чем действовать по сигналу обнаружения дрифта, ответьте на эти вопросы:
- Знаю ли я, кто сделал это изменение и почему?
- Было ли это изменение сделано во время инцидента или в условиях цейтнота?
- Обслуживает ли ресурс с дрифтом производственный трафик?
- Вызовет ли откат этого изменения известную проблему?
- Есть ли запись об этом изменении в тикете, чате или runbook?
Если ответ на первый вопрос отрицательный, начните с расследования, а не с действий. Если ресурс обслуживает трафик, предпочтите ручное восстановление автоматическому apply. Если изменение было сделано во время инцидента, рассмотрите возможность принятия дрифта после тщательной проверки.
Примирение — это не конец
После того как вы провели примирение, работа не закончена. Нужно убедиться, что примирение не создало новых проблем. Автоматический apply, откатывающий критическое исправление безопасности, может оставить систему уязвимой. Ручное изменение, принятое без тестирования, может внести нестабильность.
Цель — не устранить дрифт. Цель — обработать его так, чтобы система оставалась надёжной, а код — осмысленным. Каждое событие дрифта — это также возможность улучшить процессы. Если один и тот же дрифт появляется снова и снова, возможно, вашему пайплайну нужен защитный барьер. Если ручные изменения происходят слишком часто, возможно, в процессе реагирования на инциденты нужен более чёткий путь для обновления кода после инцидента.
Конкретный вывод
Дрифт — это не признак того, что ваша инфраструктура сломана. Это признак того, что что-то произошло за пределами вашего пайплайна. Правильный ответ зависит от контекста, а не от догмы. Перезапускайте, когда изменение было случайным. Принимайте, когда изменение было полезным. Восстанавливайте вручную, когда риск высок. И всегда, всегда понимайте, почему произошёл дрифт, прежде чем решать, что делать дальше.