Прямой ответ
Неизменяемая инфраструктура — подход, при котором работающий сервер не изменяется. Любое обновление выполняется заменой: собирается новый образ, разворачивается новый экземпляр, старый останавливается и уничтожается. Правки на работающем сервере не выполняются никогда.
Противоположный подход — изменяемая инфраструктура, где сервер живёт годами и накапливает правки. Различие определяет характер эксплуатации:
| Изменяемая | Неизменяемая | |
|---|---|---|
| Обновление | Правка на месте | Замена экземпляра |
| Дрейф конфигурации | Накапливается | Невозможен |
| Откат | Ручное восстановление состояния | Развёртывание прежнего образа |
| Время жизни сервера | Годы | Часы или дни |
| Воспроизводимость | Не гарантирована | Полная |
Ключевое следствие — устранение дрейфа конфигурации. Если сервер не изменяется после создания, его состояние полностью определяется образом, а образ собирается из кода. Расхождение между описанным и фактическим состоянием исчезает как возможность; о проблеме — в статье про дрейф конфигурации.
Второе следствие — откат заменой образа. Возврат к предыдущей версии не требует восстановления состояния: разворачивается прежний образ, который заведомо работал.
Разделение этапов сборки, выпуска и запуска — основа подхода. Образ собирается один раз, а в разных окружениях меняется только конфигурация:
1. Сборка: код + зависимости -> образ (один раз)
2. Выпуск: образ + конфигурация окружения -> релиз
3. Запуск: развёртывание релиза
Если сборка выполняется отдельно для каждого окружения, образы различаются, и проверка в тестовой среде не гарантирует поведения в продуктивной.
В Kubernetes принцип встроен в модель: развёртывание создаёт новые поды из нового образа, старые завершаются после готовности новых:
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
Параметр maxUnavailable: 0 означает, что число доступных подов не уменьшается, поэтому замена происходит без потери ёмкости; о схемах развёртывания — в статье про blue-green.
Для виртуальных машин тот же принцип реализуется сборкой образа инструментом вроде Packer: образ собирается из описания, проверяется и используется для запуска экземпляров; о подходе — в статье про инфраструктуру как код.
Практика: переход к неизменяемой инфраструктуре
1. Перенесите настройку в сборку образа. Пакеты, конфигурационные файлы и зависимости устанавливаются при сборке, а не при первом запуске сервера.
2. Разделите образ и конфигурацию. Образ одинаков для всех окружений, а параметры окружения передаются при запуске через переменные или объекты конфигурации.
3. Собирайте образ один раз. Один и тот же образ проходит тестовую среду и попадает в продуктивную. Пересборка для продуктивной среды обесценивает проверку.
4. Запретите доступ на запись к работающим серверам. Возможность ручной правки делает подход формальным: дрейф вернётся при первом инциденте.
5. Автоматизируйте замену. Развёртывание создаёт новые экземпляры и завершает старые без ручного участия.
6. Храните несколько версий образов. Откат требует доступности прежнего образа, поэтому образы не удаляются сразу после выпуска новой версии.
7. Проверяйте готовность перед переключением. Новый экземпляр принимает трафик только после прохождения проверок; о механизмах — в статье про health check.
8. Учитывайте состояние. Сервер с локальными данными не заменяется без переноса состояния, поэтому состояние выносится во внешние системы.
Рекомендации:
- Начинайте с новых сервисов. Перевод существующего сервера с многолетней историей правок сложнее развёртывания нового сервиса по неизменяемой модели.
- Выносите состояние наружу. Файлы, сессии и очереди хранятся во внешних системах, чтобы замена экземпляра не теряла данные.
- Фиксируйте версии образов. Тег, изменяющийся при каждой сборке, делает развёртывание невоспроизводимым.
- Проверяйте образ до развёртывания. Тесты выполняются на собранном образе, а не только на коде в репозитории.
- Измеряйте время замены. Замена экземпляра должна занимать минуты, иначе откат становится медленнее исправления на месте.
Практический сценарий: устранение повторяющегося сбоя переходом на замену образов
Контекст: веб-сервер на виртуальной машине требовал ручной правки конфигурации примерно раз в месяц. После каждой правки поведение немного отличалось от предыдущего, а разбор занимал часы.
- Диагностика. Конфигурационный файл содержал правки, внесённые за два года. Часть из них была утрачена при восстановлении сервера из резервной копии, что и вызывало повторяющиеся сбои.
- Причина. Сервер настраивался вручную и изменялся на месте. Описание конфигурации существовало, но отставало от фактического состояния на десятки правок.
- Действия. (а) Конфигурацию привели к единому описанию, убрав устаревшие правки; (б) сборку образа автоматизировали: базовая система, пакеты и конфигурация устанавливались при сборке; (в) развёртывание выполнялось заменой экземпляра с проверкой готовности; (г) доступ на запись к работающему экземпляру закрыли; (д) отработку отката проверили развёртыванием прежней версии образа.
- Результат. Ручные правки прекратились, а сбои после восстановления исчезли, поскольку состояние экземпляра полностью определяется образом. Замена занимает четыре минуты, откат — столько же.
Вывод: неизменяемая инфраструктура устраняет класс проблем, связанных с накопленным состоянием сервера. Условие применимости — вынесенное наружу состояние и запрет ручных правок: без запрета дрейф возвращается, и преимущества подхода теряются.
FAQ
Можно ли применять подход к серверам с базой данных? Да, при вынесенном состоянии: данные хранятся на отдельном томе либо в управляемой службе, а экземпляр заменяется без потери данных.
Чем неизменяемая инфраструктура отличается от контейнеров? Контейнеры — удобная форма реализации, но подход применим и к виртуальным машинам через сборку образов.
Как выполнять срочные исправления? Сборкой нового образа и заменой экземпляра. Если это слишком долго, временная правка допустима с обязательным переносом в описание.
Что делать с локальными файлами и сессиями? Выносить во внешнее хранилище. Локальное состояние делает замену экземпляра потерей данных.
Источники: HashiCorp Packer docs, Kubernetes docs (Deployment), The Twelve-Factor App — ссылки в шапке.