VDS · Docker и контейнеры

Обновление контейнеров без простоя

Как обновлять образы так, чтобы сервис не лёг и можно было откатиться: фиксация версий, проверка здоровья, порядок действий и автоматизация.

Обновлено 23 августа 2026 г.

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

Порядок, который работает

cd /opt/myapp
docker compose pull
docker compose up -d
docker compose ps
docker compose logs -f --tail 100

Compose пересоздаёт только те службы, чей образ изменился, остальные не трогает. Простой — секунды на перезапуск контейнера.

Но прежде чем это делать, соблюдите два условия.

Первое: версии зафиксированы. В файле должно стоять postgres:17.2, а не postgres:latest. Иначе pull однажды принесёт мажорную версию, которая перепишет формат данных, и откат станет невозможен.

Второе: копия свежая. Обновление, которое ломает базу, ломает её необратимо. Перед сменой мажорной версии — выгрузка, см. что копировать.

Замена без разрыва

Для веб-сервиса за обратным прокси простой сводится почти к нулю, если у контейнера есть проверка здоровья: прокси начнёт слать запросы только в готовый экземпляр.

services:
  app:
    image: ghcr.io/example/app:1.5.0
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
      interval: 5s
      timeout: 3s
      retries: 6
      start_period: 20s
docker inspect -f '{{.State.Health.Status}}' <контейнер>

Без проверки здоровья Compose считает контейнер готовым сразу после старта процесса — а приложение в этот момент ещё читает настройки и накатывает миграции.

Не удаляйте старый образ, пока новая версия не проработала хотя бы час. Откат — это вернуть image: ...:1.4.2 и выполнить docker compose up -d, но только пока старый образ лежит на диске. docker image prune -a сразу после обновления лишает вас этой возможности.

Откат

sed -i 's|app:1.5.0|app:1.4.2|' compose.yaml
docker compose up -d app
docker compose logs -f --tail 50 app

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

Автоматизация: осторожно

Watchtower умеет обновлять контейнеры сам. Для домашних сервисов это удобно, для боевых — риск: обновление приедет ночью, сломает базу, и никто не увидит. Разумный компромисс — только уведомления:

services:
  watchtower:
    image: containrrr/watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --monitor-only --schedule "0 0 6 * * *"

Вы узнаёте, что вышла новая версия, и обновляете руками в удобное время.

Перезагрузка машины

Пакеты системы обновляются отдельно от контейнеров. После обновления ядра нужна перезагрузка, и контейнеры с restart: unless-stopped поднимутся сами. Проверьте это заранее — командой sudo reboot в спокойное время, а не во время аварии. Мягкая перезагрузка из панели работает, пока в системе установлен qemu-guest-agent.

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

  • pull без up -d. Новый образ скачан, но работает по-прежнему старый контейнер.
  • Диск забит старыми образами. Раз в месяц docker image prune — но не сразу после обновления. См. место на диске.
  • Обновили всё разом. Ломается — непонятно что именно. Обновляйте по одной службе.
  • Не прочитали примечания к выпуску. Несовместимый файл настройки — самая частая причина отказа после смены мажора; разбор — в частых проблемах Docker.