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

Что это такое

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

Почему это важно

Неизменяемость — то, что делает замену дешёвой. Если экземпляр собран из образа, который никогда не меняется после публикации, то новая версия — это новый образ и перезапуск, а не заплатка, наложенная руками на машину, которую никто не может воспроизвести. Декларативная конфигурация делает эту замену автоматической: платформа сравнивает желаемое состояние с фактическим и действует, будь различие новой версией или упавшим подом. Сочетание этих двух вещей — причина, по которой плавное развёртывание может быть обычным событием, а не отдельным проектом.

Ключевые идеи

Образ — артефакт сборки, и он должен быть неизменяемым

Каждая сборка порождает тег или дайджест, который указывает ровно на один набор байтов. Развернуть значит указать новый тег; откатиться — указать предыдущий. Перезапись существующего тега разрушает это свойство, потому что на одно имя теперь отвечают две разные сборки, и в кластере может оказаться любая из них.

реестр:        myapp:1.4.2  (собран один раз, никогда не переиспользуется)
развёртывание: желаемый образ -> myapp:1.4.2
откат:         желаемый образ -> myapp:1.4.1

Конфигурация приходит из окружения

Образ несёт код; окружение несёт то, что различается между развёртываниями: эндпоинты, настройки функций, учётные данные. Секреты приходят из хранилища секретов платформы, а не запекаются в образ, поэтому один и тот же артефакт может работать в любом окружении. Это то, что мешает продвижению сборки превращаться в пересборку.

Желаемое состояние — это интерфейс

Вы объявляете реплики, запросы ресурсов, порты и проверки работоспособности; платформа непрерывно приводит реальность в соответствие с ними. Значит, вручную перезапущенный или удалённый экземпляр — не особое событие, а дрейф, который платформа исправляет. Значит также, что ошибка в объявлении применяется добросовестно и повторно, поэтому конфигурация заслуживает ревью не меньше кода.

Проверки работоспособности решают, восстанавливается ли система

Проверка живости отвечает на вопрос «этот процесс ещё способен работать?», а проверка готовности — «он уже готов принимать трафик?». Ошибка в них — это то, как самовосстанавливающаяся система превращается в самоперезапускающийся цикл: проверка живости, зависящая от медленного внешнего сервиса, убьёт здоровый процесс под нагрузкой. Различать эти две проверки — небольшое решение с большими последствиями.

Конвейер сборки — часть дизайна

Поскольку артефакт собирается один раз и продвигается, конвейер должен собрать, протестировать и опубликовать образ, а затем развернуть именно этот образ. Пересборка для каждого окружения возвращает тот дрейф, который контейнер должен был убрать. Конвейер — то место, где неизменяемость либо сохраняется, либо тихо оставляется.

Практика

Упакуйте сервис как неизменяемый артефакт

Возьмите небольшой сервис, напишите определение контейнера, устанавливающее его зависимости на этапе сборки, и пометьте результат версией. Затем запустите его дважды с разными значениями окружения и убедитесь, что образ не изменился.

Готово, когда: один и тот же дайджест образа работает с двумя наборами конфигурации, и ни один файл внутри образа не отличается.

Разделите живость и готовность

Для этого сервиса напишите проверку живости, зависящую только от процесса, и проверку готовности, включающую его зависимости. Опишите, что произойдёт, если зависимость медленная.

Готово, когда: медленная зависимость делает сервис неготовым, но не приводит к его перезапуску.

Частые ошибки

  • Перезаписывать теги образов — две сборки делят одно имя, и откат становится угадыванием; исправить: публикуйте неизменяемые теги или дайджесты.
  • Запекать конфигурацию в образ — для каждого окружения нужна пересборка, и дрейф возвращается; исправить: передавайте конфигурацию через окружение.
  • Использовать внешнюю зависимость как проверку живости — здоровый процесс убивают, когда зависимость медленная; исправить: держите живость локальной, а зависимости — в готовности.
  • Править работающий экземпляр, чтобы что-то починить — следующая сверка уберёт изменение; исправить: измените объявление и разверните заново.
  • Пересобирать под каждое окружение — протестирован не тот артефакт, который выпускается; исправить: соберите один раз и продвигайте тот же образ.

Что читать дальше