К основному содержимому

Перенос Docker-контейнеров между серверами

Миграция · 03.02.2025 · 5 мин чтения
Иллюстрация к статье «Перенос Docker-контейнеров между серверами»

Перенос Docker-контейнеров между серверами сводится к трём вещам: образам, томам с данными и конфигурации окружения. Контейнер сам по себе не хранит состояние — всё важное лежит в volume и в переменных .env, поэтому «перенести контейнер» на практике означает перенести образ и данные, а затем поднять его заново на новом хосте. Если Docker на новом сервере ещё не установлен, начните с базовой установки Docker на VPS, а для многоконтейнерных проектов пригодится статья про Docker Compose.

Метод 1: docker save + docker load

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

# На старом сервере — сохраняем образ со всеми слоями
docker save myapp:latest | gzip > myapp.tar.gz

# Передаём на новый сервер
scp myapp.tar.gz root@NEW_SERVER:/tmp/

# На новом сервере — загружаем образ
docker load < /tmp/myapp.tar.gz

# Проверяем, что образ на месте и с тем же ID
docker images | grep myapp

Минус метода — размер файла: образ с толстым базовым слоем (например, полный Ubuntu вместо Alpine) легко выходит за несколько гигабайт, и передача по медленному каналу занимает часы.

Метод 2: через Docker Registry (рекомендуется)

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

# Тегируем и пушим в Registry
docker tag myapp:latest registry.example.com/myapp:latest
docker push registry.example.com/myapp:latest

# На новом сервере
docker login registry.example.com
docker pull registry.example.com/myapp:latest

Если используете docker-compose, для переноса достаточно скопировать docker-compose.yml и тома данных — образы пересоберутся локально или скачаются из Registry командой docker compose up -d.

Разбор типичных ошибок при переносе

  • Error response from daemon: conflict: unable to delete ... (must be forced) — образ используется другим тегом или запущенным контейнером; сначала остановите контейнеры, использующие образ, либо добавьте флаг -f к docker rmi.
  • open /tmp/myapp.tar.gz: no such file or directory — scp оборвался на середине передачи или указан не тот путь; проверьте размер файла на обеих сторонах командой ls -la и сверьте контрольную сумму sha256sum.
  • unauthorized: authentication required — на новом сервере не выполнен docker login к приватному Registry либо истёк токен доступа.
  • Error: No such image: myapp:latest — опечатка в теге при docker tag или образ не был запушен до попытки pull на другом сервере.
  • toomanyrequests: You have reached your pull rate limit — анонимные запросы к Docker Hub ограничены по IP; выполните docker login с учётной записью или используйте собственный Registry.

Перенос томов (volumes)

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

# Экспорт тома во временный архив
docker run --rm -v myapp_data:/data -v $(pwd):/backup \
  alpine tar czf /backup/volume_backup.tar.gz -C /data .

# Импорт на новом сервере в заранее созданный том
docker volume create myapp_data
docker run --rm -v myapp_data:/data -v $(pwd):/backup \
  alpine tar xzf /backup/volume_backup.tar.gz -C /data

Сравнение способов переноса

Критерийdocker save/loadDocker Registry
Что передаётсяПолный архив образаТолько новые слои
Нужен ли отдельный сервисНетДа, Registry
Откат на прошлую версиюНужно хранить старые архивы вручнуюПросто смена тега
Подходит дляРазового переезда одного сервераРегулярных деплоев и нескольких серверов

Когда эти способы не подходят

  • Контейнер держит открытое сетевое соединение с состоянием (например, поднятую WebSocket-сессию) — перенос всегда рвёт такие соединения, нужен маршрут с graceful shutdown на уровне приложения.
  • Контейнер завязан на устройства хоста через --device (GPU, USB-токен) — образ переедет, но без такого же устройства на новом сервере часть функциональности не заработает.
  • Данные меняются во время экспорта тома — если приложение не остановлено, tar на живом volume базы данных может забрать файл в несогласованном состоянии; для СУБД переносите не файлы тома, а дамп средствами самой базы.

Чеклист миграции Docker

ШагСтатус
Установить Docker на новом сервере⬜
Перенести docker-compose.yml⬜
Перенести образы или настроить pull из Registry⬜
Перенести тома данных⬜
Обновить .env файлы⬜
Проверить на новом сервере⬜
Переключить DNS⬜

Проверка после переноса

Перед переключением DNS убедитесь, что стек работает на новом сервере так же, как на старом.

# Все контейнеры подняты и без перезапусков
docker compose ps

# Логи без ошибок за последние 5 минут
docker compose logs --since=5m

# Приложение отвечает по внутреннему порту
curl -I http://127.0.0.1:8080/health

# Данные совпадают: сверяем количество строк в ключевой таблице
docker exec -it myapp_db psql -U app -c "SELECT count(*) FROM orders;"

Если счётчики и логи совпадают со старым сервером, переключайте DNS и только после этого останавливайте контейнеры на старой машине.

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

Статья помогла?
← Назад в базу знаний Задать вопрос поддержке