Обновление приложения в Docker Compose: фиксируем версию и готовим откат

После обновления API контейнер запущен, но оформление заказа завершается ошибкой. Старый образ сохранён, поэтому кажется, что достаточно вернуть его имя. Однако новая версия уже могла изменить схему PostgreSQL, записать данные в новом формате или отправить сообщение во внешнюю очередь. Чтобы откат был доступным действием, его условия нужно определить до пересоздания контейнера.

Определяем, что меняет этот релиз

Разделите изменения приложения, конфигурации и базы. В этой процедуре обновляется только сервис api, а PostgreSQL уже работает в том же Compose-проекте. У приложения есть согласованный healthcheck и отдельный проверочный запрос к бизнес-функции. Миграции либо отсутствуют, либо выполнены расширяющим способом, совместимым со старой версией. Если это условие не выполняется, перед релизом нужен другой план восстановления.

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

Готовим две конфигурации для одного проекта

В существующем compose.yaml у сервиса api задайте image: ${APP_IMAGE:?set APP_IMAGE}. Остальные параметры приложения остаются в этом файле. Создайте release-old.env и release-new.env со значениями APP_IMAGE для соответствующих образов, например registry.example.com/team/api:2026-10-20 и registry.example.com/team/api:2026-10-29. Это заполнители ваших опубликованных релизов, а не доступные учебные образы.

У переменных shell при интерполяции Compose приоритет выше, чем у --env-file. Удалите унаследованную APP_IMAGE из окружения shell и перед обновлением проверьте config --images для обоих файлов релиза. Перед откатом повторите проверку для release-old.env: переменная из терминала не должна подменять выбранный файл. Для автоматизированного запуска удобно задавать контролируемое окружение процесса и сохранять проверенный список образов вместе с номером релиза. Именно фактическая конфигурация определяет, что будет пересоздано.

docker compose -p shop --env-file release-old.env config --images
docker compose -p shop --env-file release-new.env config --images
docker compose -p shop --env-file release-new.env config --quiet
docker compose -p shop --env-file release-new.env pull api

Во всех командах используется один project name shop: обновляем существующее окружение. Если рабочий проект называется иначе, подставьте его фактическое имя. pull загружает образ и не заменяет работающий контейнер. Поэтому ошибку доступа к registry можно обнаружить до остановки прежнего приложения. config проверяет итоговую конфигурацию; вывод полного config может содержать чувствительные значения, и хранить его нужно соответственно.

До запуска выберите окно изменения и ответственного за решение. Один контейнер Compose обычно пересоздаётся с перерывом в обслуживании; эта команда не реализует постепенный rolling update. Если запросы должны идти непрерывно, нужна отдельная схема нескольких экземпляров и переключения трафика. Наличие reverse proxy само по себе не организует безопасный переход между версиями.

Обновляем только нужный сервис

docker compose -p shop --env-file release-new.env up -d --no-deps --wait --wait-timeout 90 api
docker compose -p shop --env-file release-new.env ps api
docker compose -p shop --env-file release-new.env logs --tail 100 api

--no-deps оставляет зависимости вне этого запуска: база не должна случайно обновиться вместе с API. --wait ожидает состояние running или healthy в зависимости от наличия healthcheck. Если healthcheck не задан, живой процесс может пройти ожидание, даже когда API ещё не отвечает. Убедитесь, что проверка в Compose действительно обнаруживает важное состояние приложения.

После технической готовности выполните заранее выбранный запрос через обычный вход приложения. Например, прочитайте тестовый заказ и проверьте его поля. Для проверки записи используйте изолированные тестовые данные и предусмотренную очистку: случайная отправка реального платежа не должна становиться smoke test. Сравните ошибки, задержки и ответы с условиями принятия релиза, записанными до запуска.

Возвращаем приложение, если база совместима

docker compose -p shop --env-file release-old.env config --images
docker compose -p shop --env-file release-old.env up -d --no-deps --wait --wait-timeout 90 api
docker compose -p shop --env-file release-old.env ps api
docker compose -p shop --env-file release-old.env logs --tail 100 api

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

Восстановление базы из резервной копии — отдельная процедура с возможной потерей записей после момента копирования. Оно не должно скрываться за словом «откат». Если релиз требует такого сценария, заранее согласуйте остановку записи, точку восстановления и действия с внешними системами. Архив базы не отменит уже отправленное письмо или проведённую оплату.

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

Завершённый релиз оставляет короткий протокол: прежняя и новая конфигурации, результат healthcheck, результат бизнес-запроса и принятое решение. При неудаче добавьте результат возврата. Такой порядок позволяет продолжать работу по наблюдаемым условиям, а не считать зелёный статус контейнера доказательством исправности всего приложения.

Ещё по теме

Продолжить изучение

Хотите разобраться в контейнеризации целиком, от образа до работающего окружения? Сборка, сети, данные и запуск приложений входят в программу «Docker и Docker Compose: контейнеризация приложений».

Продолжить на практике

  • Docker и Docker Compose: контейнеризация приложений ↗

    Упакуйте приложение в Docker и запустите его с PostgreSQL через Compose. Образы, сети, тома, диагностика поломок, обновление версий и восстановление данных — с практикой и итоговым проектом.