Как восстановить Docker-приложение на новом сервере из резервной копии

После переноса Docker-контейнеры могут запуститься без ошибок, а приложение — показать пустую базу, потерять загруженные файлы или перестать принимать пароли. Поэтому восстановление заканчивается не командой docker compose up -d, а проверкой данных и действий, ради которых работает сервис.

Чтобы восстановить Docker-приложение на новом сервере, нужно вернуть конфигурацию, подключить постоянные хранилища, восстановить базу и только после проверки переключить пользователей. Ниже разберём этот порядок на примере Linux VPS с Docker Compose и PostgreSQL. Для MySQL, MariaDB и других вариантов хранения есть отдельные пояснения.

Область применения: один сервер с Docker Compose. Для Kubernetes, Docker Swarm и кластеров баз данных потребуется учитывать их собственный порядок восстановления.

Содержание

Что должно быть в резервной копии Docker-приложения

Сначала проверьте состав копии. Один архив с Docker-образом обычно не содержит всего, что нужно для восстановления работающего проекта.

Что сохранить Для чего это нужно
compose.yaml или docker-compose.yml, дополнительные Compose-файлы Воссоздать сервисы, подключения, порты, команды запуска и ограничения ресурсов.
.env, файлы secrets и конфигурация приложения Вернуть настройки подключения, ключи шифрования, параметры авторизации и интеграций.
Дамп базы или корректная физическая копия СУБД Восстановить пользователей, заказы, документы и другие записи приложения.
Данные volumes и bind mounts Вернуть загрузки пользователей, вложения и другие файлы, которые приложение хранит отдельно от базы.
Конфигурация reverse proxy, сертификаты и связанные ключи Восстановить маршрутизацию домена и HTTPS. Сертификат также можно выпустить заново подходящим способом.
Точные версии или digest образов Запустить ту же версию приложения и базы. Для собственного образа нужен доступ к registry, сохранённый образ или исходники с воспроизводимой сборкой.

docker image save сохраняет образы. docker export выгружает файловую систему контейнера, но не содержимое подключённых volumes. Ни одна из этих команд сама по себе не создаёт полную резервную копию приложения.

Отдельно проверьте внешние зависимости: S3-хранилище, удалённую базу, Redis, очередь сообщений, SMTP и задания cron на самом сервере. Их содержимое и настройки могут вообще не входить в копию Docker-проекта.

Какие данные получится вернуть из бэкапа

Запишите дату и время копии с часовым поясом. Если последняя пригодная копия создана в 03:00, а сервер потерян в 11:00, обычное восстановление из этой копии не вернёт изменения за следующие восемь часов. Для них нужны дополнительные источники: например, архив WAL PostgreSQL, binlog MySQL или более свежая копия.

База и файлы должны соответствовать друг другу. Дамп может содержать запись о загруженном документе, которого ещё нет в архиве uploads. Бывает и обратная ситуация: файл сохранён, а связанная с ним запись не попала в базу.

Если старый сервер работает: перед финальной копией включите режим обслуживания, остановите фоновые обработчики и другие процессы, которые меняют данные. Затем сделайте дамп и копию файлов в пределах одной паузы записи. Саму PostgreSQL для логического дампа останавливать не требуется.

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

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

Шаг 1. Подготовьте новый VPS

Для восстановления нужны Linux, SSH-доступ, Docker Engine и плагин Docker Compose. Команды ниже рассчитаны на Bash и административные права. Выполняйте их на новом сервере, если явно не указано другое.

docker version
docker compose version
uname -m
free -h
df -h
df -i

Проверьте результат:

  • docker version должен показывать доступный Docker Engine, а не только установленный клиент.
  • docker compose version должен завершаться без ошибки.
  • Архитектура сервера должна поддерживаться вашими образами. Образ только для amd64 не стоит автоматически считать пригодным для arm64.
  • На диске должно хватать места одновременно для архива, распакованных файлов, восстановленной базы, индексов, образов и временного роста журналов.
  • Свободные гигабайты не исключают нехватку inode: это особенно заметно при большом количестве мелких файлов.

Не рассчитывайте размер диска по сжатому бэкапу. Архив на 5 ГБ после распаковки может занимать существенно больше, а восстановление базы потребует дополнительного места.

При выборе VPS/VDS Xhost24 ориентируйтесь на фактическое потребление приложения и базы. Кроме обычной нагрузки учтите место под восстановление и последующие резервные копии.

На время проверки ограничьте доступ к новому приложению своим IP или используйте SSH-туннель. PostgreSQL, MySQL и Redis для связи между контейнерами обычно не требуется публиковать в интернет. Публикация порта Docker без адреса привязки может открыть его на внешних интерфейсах.

Шаг 2. Перенесите и проверьте резервную копию

В примере комплект копии размещён в /srv/restore:

/srv/restore/
├── project/
│   ├── compose.yaml
│   ├── .env
│   └── proxy/
├── appdb.dump
├── uploads.tar.gz
└── SHA256SUMS

project содержит конфигурацию проекта, appdb.dump — дамп PostgreSQL в custom-формате, а uploads.tar.gz — содержимое файлового тома. У вашего бэкапа могут быть другие имена и структура: сопоставьте их с примером до выполнения команд.

Создайте каталоги:

install -d -m 700 /srv/restore /srv/myapp

Передайте файлы по SFTP, SCP или rsync через SSH. Учётной записи, которой выполняется передача, нужны права на каталог назначения. Не размещайте архивы в публичном каталоге сайта.

Если при создании копии был сохранён файл SHA256SUMS с относительными путями, проверьте его:

cd /srv/restore
sha256sum -c SHA256SUMS

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

Проверьте архив файлов и посмотрите его структуру:

set -o pipefail
gzip -t uploads.tar.gz
tar -tzf uploads.tar.gz | sed -n '1,20p'

gzip -t при успехе обычно ничего не выводит. Ошибка означает, что продолжать распаковку как исправного архива нельзя. Проверка списка файлов также должна завершиться без ошибок.

Обратите внимание на начало путей: ./photo.jpg, uploads/photo.jpg и data/uploads/photo.jpg требуют разной распаковки. Ниже предполагается, что в архиве лежит непосредственно содержимое тома, без дополнительного родительского каталога.

Совпадение хешей и исправный архив подтверждают целостность файлов копии. Пригодность базы и полноту восстановления ещё предстоит проверить.

Шаг 3. Восстановите Compose, .env и настройки

Скопируйте конфигурацию в новый каталог проекта. Каталог /srv/myapp в этом примере должен быть новым, без другого работающего приложения.

cp -a /srv/restore/project/. /srv/myapp/
chmod 600 /srv/myapp/.env
cd /srv/myapp

docker compose config -q
docker compose config --services
docker compose config --images

Первая проверка должна завершиться без ошибок. Следующие команды покажут имена сервисов и образы. Полный вывод docker compose config может содержать подставленные пароли и токены, поэтому не публикуйте его без проверки.

Далее используются условные имена:

  • app — приложение;
  • db — PostgreSQL;
  • proxy — reverse proxy;
  • uploads и pgdata — ключи томов в Compose;
  • appdb — исходная база, app_restore — новая база для восстановления;
  • appuser — исходный владелец объектов приложения, postgres — администратор PostgreSQL.

Замените эти имена на свои. Если проект запускается с несколькими файлами -f, отдельным --env-file или профилями, используйте тот же набор параметров во всех дальнейших командах.

До запуска проверьте:

  • Версии. Верните версию приложения и СУБД, с которыми создана копия. Перенос и обновление лучше проводить отдельно. Для образов сохраните точные версии, а при наличии — digest.
  • Подключение к базе. В обычной Compose-сети приложение обращается к имени сервиса, например db:5432. localhost внутри контейнера указывает на сам этот контейнер.
  • Пути. Все bind mounts, файлы конфигурации и secrets должны существовать на новом сервере.
  • Внешние ресурсы. Проверьте external networks, удалённые хранилища и адреса зависимостей. Новый экземпляр не должен случайно писать в старую рабочую базу.
  • Ключи. Восстановите исходные ключи шифрования приложения. Новый случайный ключ может сделать сохранённые данные и учётные данные интеграций нечитаемыми.
  • Автоматические действия. На время проверки отключите рабочие рассылки, списания, исходящие вебхуки и встроенные планировщики штатными настройками приложения.

Файл .env не всегда передаётся в контейнер целиком: Compose может только подставлять его значения в YAML. Сохраните исходную связь между .env, environment, env_file и файлами secrets.

После проверки версий загрузите образы:

docker compose pull

Для закрытого registry предварительно потребуется авторизация. Если собственный образ сохранён в архиве, загрузите его командой docker load -i /srv/restore/images.tar. Для сервисов с build: понадобятся исходники и файлы сборки.

Шаг 4. Восстановите volumes и bind mounts

Именованные тома: как избежать подключения пустого хранилища

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

В существующем разделе volumes файла Compose укажите:

volumes:
  uploads:
    external: true
    name: restore_uploads
  pgdata:
    external: true
    name: restore_pgdata

Это фрагмент конфигурации, а не полный Compose-файл. Сохраните остальные тома и используйте реальные ключи вашего проекта. Подключения внутри сервисов должны ссылаться на эти ключи. Например, для рассматриваемого приложения и PostgreSQL 17:

# В сервисе app:
volumes:
  - uploads:/app/uploads

# В сервисе db с PostgreSQL 17:
volumes:
  - pgdata:/var/lib/postgresql/data

Путь приложения берите из его исходной конфигурации. Для официального образа PostgreSQL 18 и новее изменены стандартные PGDATA и точка подключения тома; механически переносить в него пример для PostgreSQL 17 нельзя.

external: true означает, что Compose должен найти уже существующий том и выдаст ошибку, если его нет. Это помогает заметить неверное имя вместо незаметного создания пустого хранилища.

Создайте новые тома. Следующий блок откажется продолжать, если одно из имён уже занято:

(
  set -eu
  for restore_volume in restore_uploads restore_pgdata; do
    if docker volume inspect "$restore_volume" >/dev/null 2>&1; then
      echo "Том $restore_volume уже существует. Выберите новое имя."
      exit 1
    fi
  done
  docker volume create restore_uploads
  docker volume create restore_pgdata
)

Если получили отказ, выберите свободные имена и измените их в Compose и дальнейших командах. Не очищайте существующие тома ради продолжения инструкции.

Восстановите файлы приложения:

docker run --rm --network none --user 0:0 \
  --mount type=volume,src=restore_uploads,dst=/data,volume-nocopy \
  --mount type=bind,src=/srv/restore,dst=/backup,readonly \
  ubuntu:24.04 sh -ec \
  'test -z "$(ls -A /data)"; tar --numeric-owner -xzpf /backup/uploads.tar.gz -C /data'

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

Если в архиве есть лишний верхний каталог, скорректируйте распаковку по его фактической структуре. Не добавляйте --strip-components наугад: иначе файлы могут оказаться не там, где их ожидает приложение.

Том restore_pgdata пока остаётся пустым. В основном сценарии база будет восстановлена из дампа. Архив файлов базы поверх него распаковывать не нужно.

Если вместо volume используется каталог сервера

Запись ./uploads:/app/uploads означает bind mount. В нашем каталоге проекта приложение ожидает файлы в /srv/myapp/uploads. Восстановите их именно туда, в новый пустой каталог, с сохранением владельцев и прав. Создание именованного тома не заменяет такой bind mount.

Если исходный путь был абсолютным, например /data/uploads, восстановите этот путь или осознанно измените его в Compose. Относительные пути тоже проверьте: они зависят от расположения Compose-файла.

Шаг 5. Восстановите PostgreSQL из дампа

Запустите только базу

Приложение пока не запускайте: оно может создать собственную схему или выполнить миграции до импорта.

cd /srv/myapp
docker compose config -q
docker compose up -d --no-deps db
docker compose logs --tail=50 db
docker compose exec -T db pg_isready -U postgres

Дождитесь завершения первоначальной инициализации в логах и ответа accepting connections. Этот ответ означает готовность принимать подключения, но ещё не подтверждает наличие данных приложения.

В примере используется официальный образ PostgreSQL 17 и локальное подключение администратора postgres внутри контейнера. Если у вас другое имя администратора или изменённая аутентификация, используйте действующие параметры доступа. Не отключайте проверку паролей для обхода ошибки.

Проверьте формат дампа

docker compose exec -T db pg_restore --list \
  < /srv/restore/appdb.dump \
  > /srv/restore/appdb.contents.txt

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

pg_restore используется для custom- и других поддерживаемых архивных форматов PostgreSQL. Обычный текстовый SQL-файл восстанавливается через psql. Расширение файла само по себе формат не гарантирует.

Подготовьте роли и новую пустую базу

Дамп одной базы не создаёт глобальные роли PostgreSQL. До импорта восстановите роли, на которые ссылается копия. Для простого примера все объекты приложения принадлежат роли appuser.

Откройте psql:

docker compose exec db psql -U postgres -d postgres

Посмотрите существующие роли командой \du. Если appuser отсутствует, создайте её и задайте пароль, совпадающий с настройками подключения приложения:

CREATE ROLE appuser LOGIN;
\password appuser
\q

Если владельцев и групп несколько, восстановите их по исходной конфигурации или сохранённому файлу ролей. Для подготовки такой копии PostgreSQL предоставляет pg_dumpall --roles-only. Перед импортом файла ролей на новый сервер нужно проверить пересечения с уже созданными ролями, включая администратора.

Теперь создайте отдельную пустую базу:

docker compose exec -T db createdb \
  -U postgres --owner=appuser --template=template0 app_restore

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

Выполните импорт

docker compose exec -T db pg_restore \
  -U postgres -d app_restore --exit-on-error --single-transaction \
  < /srv/restore/appdb.dump

-T отключает псевдотерминал при передаче файла. --exit-on-error прекращает восстановление при ошибке, а --single-transaction применяет импорт одной транзакцией: либо он завершается целиком, либо его изменения откатываются.

Команда должна завершиться с кодом 0. Не игнорируйте ошибки отсутствующих ролей, расширений и прав. Добавление --no-owner или --no-privileges меняет результат восстановления; это не универсальное исправление.

Для очень больших баз восстановление одной транзакцией может потребовать другой организации работы. Параллельный импорт через --jobs нельзя совмещать с --single-transaction; он также требует подходящего файлового формата и не работает с таким вводом через stdin.

Проверьте восстановленную базу

docker compose exec -T db psql \
  -X -v ON_ERROR_STOP=1 -U postgres -d app_restore -c '\dt'

docker compose exec -T db psql \
  -X -v ON_ERROR_STOP=1 -U postgres -d app_restore -c 'ANALYZE;'

Первая команда показывает таблицы, видимые в текущем пути поиска схем. Если приложение использует отдельные схемы, проверьте и их. ANALYZE обновляет статистику для планировщика запросов.

Одного списка таблиц мало. Сверьте несколько показателей, смысл которых вам понятен: число пользователей, последние заказы, даты документов, доступность вложений. Например, если в вашей схеме действительно есть таблица public.orders с полем created_at:

SELECT count(*), max(created_at) FROM public.orders;

Сравнивайте результат с состоянием на момент копии. Более поздние заказы в старой базе не появятся из раннего дампа.

В настройках подключения приложения укажите базу app_restore, сервер db и нужную роль. Если имя базы входит в DATABASE_URL, измените его там. Изменение только POSTGRES_DB у уже инициализированного контейнера не переименует базу и не переключит приложение.

Если резервная копия — обычный SQL-файл

Вместо команды pg_restore используйте:

docker compose exec -T db psql \
  -X -v ON_ERROR_STOP=1 -U postgres -d app_restore \
  < /srv/restore/appdb.sql

Это вариант для SQL-дампа одной базы, рассчитанного на импорт в заранее созданную базу. Перед выполнением проверьте, нет ли внутри создания другой базы и команд переключения подключения. При ошибке остановитесь: обычный SQL-импорт может успеть применить часть изменений. Повторное восстановление выполняйте в новую пустую базу после устранения причины.

Что изменить для MySQL и MariaDB

Порядок остаётся тем же: подготовить конфигурацию и файловые хранилища, запустить только СУБД, восстановить данные, затем подключить приложение.

Для MySQL SQL-дамп загружается клиентом mysql. Ниже пример с новой базой app_restore. При её создании задайте исходные CHARACTER SET и COLLATE, если они отличались от настроек по умолчанию нового сервера.

docker compose exec db mysql -u root -p \
  -e 'CREATE DATABASE app_restore;'

docker compose cp /srv/restore/appdb.sql db:/tmp/restore-appdb.sql

docker compose exec db sh -c \
  'mysql -u root -p app_restore < /tmp/restore-appdb.sql'

Пароль вводится по запросу. В последней команде терминал оставлен включённым, а SQL читается из файла внутри контейнера. При ошибке импорта не продолжайте запуск приложения.

Предварительно проверьте содержимое SQL: дамп, созданный с --databases или --all-databases, может содержать собственные CREATE DATABASE и USE. Тогда имя app_restore в командной строке не заставит весь импорт попасть именно в неё.

После успешного импорта удалите временный экземпляр дампа из контейнера:

docker compose exec -T db rm /tmp/restore-appdb.sql

Восстановите пользователя приложения и его права, проверьте таблицы и измените имя базы в конфигурации приложения. Отдельно проверьте процедуры, триггеры, события и их DEFINER, если проект их использует.

Для MariaDB используйте её совместимую версию и клиент mariadb. Не совмещайте аварийное восстановление с переходом между MySQL и MariaDB без отдельной проверки совместимости.

Если готовите новую копию MySQL, mysqldump --single-transaction подходит для согласованного снимка транзакционных таблиц, например InnoDB. Он не даёт такой же гарантии для MyISAM и не решает согласованность базы с загрузками на диске. Во время дампа также нельзя произвольно менять структуру таблиц.

Шаг 6. Проверьте приложение до смены DNS

Запустите необходимые сервисы

После восстановления базы и файлов запустите приложение и reverse proxy. В примере их зависимости уже подготовлены. Если проект использует отдельный Redis или другую обязательную службу, сначала восстановите и запустите её.

docker compose up -d --no-deps app proxy
docker compose ps -a
docker compose logs --tail=100 app db proxy
docker stats --no-stream

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

Убедитесь, что приложение подключено к нужному хранилищу:

docker inspect "$(docker compose ps -q app)" \
  --format '{{range .Mounts}}{{println .Type .Name .Source "->" .Destination}}{{end}}'

Для рассматриваемого примера ожидается том restore_uploads в /app/uploads. Аналогично проверьте подключение постоянного каталога базы у сервиса db.

Откройте сайт по прежнему домену на новом IP

Проверка по одному IP может попасть на другой виртуальный хост. Для HTTPS также важны имя домена и сертификат. Команда curl позволяет направить запрос на новый сервер без изменения публичного DNS:

curl --resolve app.example.com:443:203.0.113.10 \
  -sS -o /dev/null -w 'HTTP %{http_code}\n' \
  https://app.example.com/

Замените app.example.com на свой домен, а 203.0.113.10 — на IP нового VPS. На сервере уже должен быть настроен HTTPS для этого домена. Не добавляйте -k в итоговую проверку: он скрывает проблемы сертификата.

Если приложение возвращает перенаправление, проверьте его адрес и конечную страницу. Для каждого дополнительного имени, например домена API, потребуется своя проверка.

Для проверки в браузере временно добавьте соответствие домена и нового IP в hosts на своём компьютере. После переключения удалите эту запись. Запись hosts и параметр curl влияют только на ваши запросы: внешние вебхуки продолжат использовать публичный DNS.

Проверьте действия пользователя

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

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

Убедитесь, что данные переживают пересоздание контейнеров

Обычный перезапуск контейнера сохраняет его записываемый слой. Поэтому он не выявит случай, когда приложение пишет мимо volume.

На новом сервере, до допуска пользователей, сохраните тестовую запись и файл. Затем пересоздайте контейнер базы с тем же восстановленным томом:

docker compose up -d --no-deps --force-recreate db

Дождитесь готовности базы:

docker compose exec -T db pg_isready -U postgres

После ответа accepting connections пересоздайте контейнер приложения:

docker compose up -d --no-deps --force-recreate app

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

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

Шаг 7. Переключите пользователей на новый сервер

Если старый сервер всё ещё принимает изменения, успешно проверенная копия уже может отставать. Перед переключением нужна финальная пауза записи и последняя согласованная копия.

  1. На старом сервере включите режим обслуживания и остановите все источники записи, включая фоновые задания.
  2. Сделайте финальные копии базы и файлов. Если они новее тестового восстановления, повторите восстановление в чистые целевые хранилища и краткую проверку.
  3. Подготовьте A-запись домена для нового IPv4. Отдельно проверьте AAAA: старая IPv6-запись может отправлять часть посетителей на прежний сервер.
  4. Если домен работает через CDN или прокси, обновите также адрес origin и проверьте правила доступа к нему.
  5. Переключите DNS или адрес назначения на прокси. Старый экземпляр оставьте без записи, пока к нему ещё могут приходить запросы.
  6. Включите рабочие обработчики только на выбранном новом сервере. Проверьте очереди, cron, вебхуки и отправку почты.

Для планового переноса TTL можно снизить заранее. Изменение TTL одновременно с IP не отменяет уже закешированные старые ответы.

После переключения уберите локальную запись hosts и выполните проверку через обычное разрешение DNS:

dig +short A app.example.com
dig +short AAAA app.example.com
curl -sS -o /dev/null -w 'HTTP %{http_code}\n' https://app.example.com/

Проверьте сайт также с другой сети и сопоставьте запросы с журналом нового сервера. При использовании CDN команда dig покажет адреса CDN; правильность origin подтверждайте отдельно.

Как откатиться, если после переключения обнаружилась проблема

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

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

Старый сервер и исходные копии сохраняйте до завершения проверки и согласованного срока отката. После восстановления настройте резервное копирование нового экземпляра, дождитесь успешной копии и проверьте её восстановление отдельно.

Частые ошибки после восстановления Docker-приложения

Симптом Что проверить и исправить
Приложение предлагает первоначальную настройку Проверьте имя базы, строку подключения, имя тома и путь монтирования. До выяснения причины не проходите установку: она может создать новую схему.
База восстановлена, но вложения не открываются Сопоставьте дату дампа и архива uploads, проверьте вложенность каталогов, пути и права.
Permission denied при чтении или загрузке файлов Сравните UID/GID процесса и владельцев каталога. Исправьте владельца нужного пути по требованиям образа. Не используйте chmod 777 как общее решение.
role does not exist или ошибки расширения PostgreSQL Подготовьте отсутствующие роли и совместимые расширения, затем повторите восстановление в чистую базу.
unsupported version in file header Проверьте версию pg_dump, создавшего архив, и используйте совместимый pg_restore. Не обновляйте всю СУБД наугад.
relation already exists, Table already exists, duplicate key В целевой базе уже есть объекты или остался частичный импорт. Проверьте выбранную базу, автоматическую инициализацию и восстановите в новую пустую базу.
Connection refused или ошибки авторизации базы Проверьте готовность СУБД, имя сервиса, внутренний порт, общую сеть, пользователя и пароль приложения.
502 Bad Gateway Посмотрите логи приложения и proxy, адрес upstream, порт и сеть. Убедитесь, что proxy разрешает текущее имя сервиса.
Контейнер постоянно перезапускается Проверьте его логи, код завершения, OOMKilled, свободную память и ограничения контейнера.
После смены DNS часть пользователей видит старую версию Проверьте AAAA, кеш DNS, CDN, origin и домены перенаправлений. Убедитесь, что старый сервер не продолжает принимать запись.
Письма, задания или вебхуки выполняются дважды Найдите активные обработчики на обоих серверах, задания cron хоста и встроенные планировщики приложения.

Для проверки прав в контейнере, где доступны sh, id и ls:

docker compose exec -T app sh -c 'id; ls -ldn /app/uploads'

Команда показывает числовые UID/GID пользователя и каталога. При rootless Docker, user namespaces, NFS или SELinux дополнительно учитывайте преобразование идентификаторов и правила доступа соответствующего механизма.

Для первичной проверки перезапусков:

docker inspect "$(docker compose ps -q app)" \
  --format 'Exit={{.State.ExitCode}} OOM={{.State.OOMKilled}} Restarts={{.RestartCount}}'

Значение OOM=true указывает на завершение из-за нехватки доступной памяти. Разберитесь с потреблением и лимитами; отключение ограничений без оценки ресурсов может перенести проблему на весь сервер.

Ответы на дополнительные вопросы

Можно ли восстановить приложение без старого сервера?

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

Достаточно ли одного compose.yaml?

Он описывает запуск, но обычно не содержит содержимое базы, volumes и внешних файлов secrets. Восстановить рабочие пользовательские данные только из Compose-файла нельзя.

Что делать, если сохранился только архив тома PostgreSQL или MySQL?

Определите, как создана копия. Физическую копию восстанавливают по правилам соответствующей СУБД: в отдельное пустое хранилище, с совместимой версией, нужными журналами и файлами. Для проверенной холодной копии это делают до первого запуска базы. Нельзя сначала дать новой СУБД создать файлы, а затем распаковать старый каталог поверх них.

Если каталог просто архивировали во время записи, исправность tar-файла не подтверждает исправность базы. Нужна проверка восстановления на отдельном экземпляре.

Можно ли перенести весь /var/lib/docker?

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

Нужно ли восстанавливать Redis?

Зависит от его роли. Восстанавливаемый кеш иногда допустимо создать заново. Если Redis содержит очереди, сессии или важное состояние, сначала проверьте используемую схему persistence и восстановите соответствующие данные. При одновременном использовании RDB и AOF учитывайте порядок их загрузки. Старые задания очереди могут выполниться повторно.

Как поступить с SQLite?

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

Что делать, если утрачен .env?

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

Можно ли восстановить проект без простоя?

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

Сколько времени займёт восстановление?

Сложите время передачи, распаковки, импорта, построения индексов и проверки приложения. Размер сжатого архива не позволяет надёжно оценить все эти этапы. Самая полезная оценка получается из пробного восстановления на сопоставимом сервере.

Какие команды не стоит использовать для устранения ошибок восстановления?

Не запускайте docker compose down -v, очистку volumes и удаление каталогов данных, пока не выяснили, что именно будет удалено. Такие команды не исправляют ошибку подключения или несовместимость версии и могут уничтожить оставшуюся копию данных.

Когда восстановление можно считать завершённым?

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

  • 0 Пользователи нашли это полезным
Помог ли вам данный ответ?

Связанные статьи

Как выбрать VPS и быстро его запустить

Пример типового сценария для сайта или небольшого набора проектов. Оцените нагрузку...

Какую выбрать ОС для VPS

Вопрос какую выбрать ОС для VPS часто сложнее, чем выбор тарифа. Коротко по сценариям. Linux...

Какой VPS хостинг выбрать. Основные критерии

VPS это виртуальный сервер с выделенными ресурсами. У вас есть свое окружение, свой доступ по...

Где арендовать VPS: виртуальные серверы для проектов любого масштаба

Когда встаёт вопрос, где арендовать VPS, большинство пользователей смотрит только на цену и...

Debian 12 to 13: апгрейд без сюрпризов

Debian 12 живёт годами, но в какой-то момент ты упираешься в банальные вещи: нужен свежее стек,...