Перейти к содержимому
Главная страница » Как перенести Docker-контейнеры на другой сервер: все рабочие способы — от docker save до массовой миграции 200+ контейнеров

Как перенести Docker-контейнеры на другой сервер: все рабочие способы — от docker save до массовой миграции 200+ контейнеров

Миграция Docker-контейнеров между VPS — частая задача при смене хостинга, переезде на более мощный сервер, обновлении инфраструктуры или консолидации проектов. На первый взгляд всё просто: контейнеры “упакованы”, значит их можно быстро скопировать на новый сервер. На практике же перенос почти всегда упирается не в контейнеры, а в данные, тома, переменные окружения, bind mounts, базы данных и способ запуска.

В этой статье разберём все основные способы миграции Docker на другой хост:
  • перенос одного контейнера “как есть”;
  • миграцию образов и volumes;
  • перенос Docker Compose-проекта;
  • потоковую миграцию без промежуточных файлов;
  • массовый перенос десятков и сотен контейнеров;
  • и, главное, какой способ выбрать в реальной продакшн-среде.
В качестве отправной точки возьмём популярный гайд Make Tech Easier про перенос Docker-контейнера на другой хост, а затем дополним его практикой для VPS, self-hosted сервисов и клиентских инфраструктур.

Содержание

Что именно нужно переносить в Docker

Самая частая ошибка при миграции Docker — думать, что контейнер = приложение + все данные + вся конфигурация.

На самом деле Docker-развёртывание обычно состоит из четырёх разных слоёв:

1) Docker image (образ)

Это шаблон, из которого создаётся контейнер.

2) Container runtime config

То, как контейнер был запущен:

  • переменные окружения (ENV, --env, .env);
  • проброс портов (-p);
  • сети;
  • restart policy;
  • capabilities;
  • mounts и volumes.

3) Persistent data

Это самое важное — данные, которые должны пережить перезапуск и перенос:

  • Docker volumes;
  • bind mounts;
  • базы данных;
  • пользовательские файлы;
  • кэш, если он нужен.

4) Orchestration / deployment logic

То, как это всё воспроизводится:

  • docker run;
  • docker compose;
  • Ansible / Terraform;
  • CI/CD;
  • Swarm / Nomad / Kubernetes.

Именно поэтому контейнеры сами по себе обычно не мигрируют “как VM”. Правильный перенос — это перенос образов + конфигурации + данных. Это соответствует и рекомендациям Docker: данные нужно хранить во volumes, а контейнеры — уметь пересоздавать.

Способ №1. Перенос контейнера через docker commit + docker save

Это самый популярный “быстрый” способ, который часто рекомендуют в базовых гайдах. Его суть:

  1. Остановить контейнер;
  2. Зафиксировать его текущее состояние в новый образ;
  3. Сохранить образ в .tar;
  4. Передать файл на новый сервер;
  5. Загрузить образ и запустить контейнер заново.

Именно этот подход лежит в основе гайда Make Tech Easier.

Когда этот способ подходит

Он хорош, если вы переносите:

  • один или несколько контейнеров;
  • сервисы без сложной инфраструктуры;
  • тестовые окружения;
  • прототипы;
  • контейнеры, которые были модифицированы вручную через docker exec.

Когда не подходит

Он не идеален, если:

  • у контейнера есть volumes;
  • внутри работает база данных;
  • контейнеров десятки или сотни;
  • вы хотите чистый и воспроизводимый деплой.

Пошагово: перенос одного контейнера

1. Посмотреть контейнеры

docker ps

2. Остановить контейнер

docker stop myapp

3. Сохранить текущее состояние контейнера в новый образ

docker commit myapp myapp-migrated:latest

Если контейнер не хочется останавливать, можно использовать docker commit -p=false, но это повышает риск получить неполные или несогласованные данные. Для production-сервисов лучше делать миграцию на “чистом” состоянии. Подобный риск прямо вытекает из природы commit-подхода.

4. Сохранить образ в файл

docker save -o myapp-migrated.tar myapp-migrated:latest

5. Передать файл на новый сервер

scp myapp-migrated.tar root@NEW_SERVER_IP:/root/

6. Загрузить образ на новом VPS

docker load -i /root/myapp-migrated.tar

7. Создать и запустить контейнер

docker create --name myapp -p 8080:80 myapp-migrated:latest
docker start myapp

Плюсы способа

  • просто;
  • быстро;
  • удобно для единичных контейнеров;
  • не требует реестра образов.

Минусы

  • не переносит volumes;
  • легко забыть параметры запуска;
  • плохо масштабируется;
  • не подходит как “долгосрочный DevOps-подход”.

Способ №2. Перенос volumes и данных контейнера

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

И Docker сам подчёркивает важный момент:

docker export не экспортирует содержимое volumes.
Если у контейнера подключён volume, его данные надо переносить отдельно.

Это ключевая причина, почему перенос “одного tar-файла контейнера” часто заканчивается сюрпризом: контейнер запустился, а данных внутри нет.

Как посмотреть volumes контейнера

docker inspect myapp

Или компактнее:

docker inspect -f '{{ json .Mounts }}' myapp

Официально рекомендуемый способ бэкапа volume

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

Пример: резервная копия volume

Допустим, у контейнера есть volume myapp_data.

docker run --rm \
-v myapp_data:/volume \
-v $(pwd):/backup \
ubuntu \
tar cvf /backup/myapp_data.tar /volume

На практике можно использовать и alpine, чтобы операция выполнялась быстрее и легче.

Сжатый вариант

docker run --rm \
-v myapp_data:/volume \
-v $(pwd):/backup \
alpine \
tar czf /backup/myapp_data.tar.gz -C /volume .

Как восстановить volume на новом сервере

1. Создать volume

docker volume create myapp_data

2. Развернуть архив в volume

docker run --rm \
-v myapp_data:/volume \
-v $(pwd):/backup \
alpine \
sh -c "cd /volume && tar xzf /backup/myapp_data.tar.gz"

А что с bind mounts?

Если контейнер использует не Docker volume, а обычную папку хоста, например:

-v /opt/myapp/uploads:/app/uploads

то Docker тут вообще ни при чём — это просто директория сервера, и её нужно переносить как обычные файлы:

rsync -avz /opt/myapp/uploads root@NEW_SERVER_IP:/opt/myapp/uploads

Или:

tar -czf uploads.tar.gz /opt/myapp/uploads
scp uploads.tar.gz root@NEW_SERVER_IP:/root/

Отдельно про базы данных

Если внутри Docker крутятся:

  • PostgreSQL
  • MySQL / MariaDB
  • MongoDB
  • Redis

то лучше делать не только перенос volume, но и логический backup:

PostgreSQL

docker exec -t postgres pg_dumpall -U postgres > postgres_dump.sql

MySQL / MariaDB

docker exec mysql mysqldump -u root -p --all-databases > mysql_dump.sql

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

  • дамп проще проверить;
  • его легче восстановить на новой версии;
  • он надёжнее при переносе между разными окружениями.

Способ №3. Потоковый перенос без .tar файла

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

Этот подход тоже упоминается в гайде Make Tech Easier и отлично подходит для VPS-миграций.

Пример

docker save myapp-migrated:latest | ssh root@NEW_SERVER_IP docker load

Что происходит:

  • docker save пишет образ в stdout;
  • поток идёт через SSH;
  • на новом сервере docker load сразу загружает образ.

Когда это удобно

  • мало места на диске;
  • нужно быстро перекинуть один образ;
  • серверы уже имеют SSH-доступ друг к другу.

Ограничения

  • всё равно нужно отдельно переносить volumes;
  • если связь оборвётся — передача придётся начинать заново;
  • неудобно для больших batch-миграций без автоматизации.

Способ №4. Перенос Docker Compose-проекта

Если у вас не один контейнер, а полноценный стек:

  • приложение;
  • база данных;
  • Redis;
  • reverse proxy;
  • worker;
  • cron;

то лучший способ миграции — переносить не контейнеры, а весь проект через Docker Compose.

И это уже правильный production-подход.

Docker сам позиционирует Compose как основной способ воспроизводимого развёртывания multi-container приложений.

Что нужно перенести

Обычно это:

  • docker-compose.yml
  • .env
  • nginx.conf / Caddyfile / traefik.yml
  • volumes
  • bind mounts
  • SSL / Let’s Encrypt storage
  • дампы БД

Пример Compose-конфигурации

version: "3.9"services:
app:
image: myapp:latest
ports:
- "8080:80"
env_file:
- .env
volumes:
- app_data:/app/data
restart: unless-stopped db:
image: postgres:16
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: secret
volumes:
- db_data:/var/lib/postgresql/data
restart: unless-stoppedvolumes:
app_data:
db_data:

Как мигрировать Compose-проект

На старом сервере

  1. Скопировать папку проекта:
tar -czf myproject.tar.gz /opt/myproject
  1. Сохранить volumes:
docker run --rm \
-v myproject_app_data:/volume \
-v $(pwd):/backup \
alpine \
tar czf /backup/app_data.tar.gz -C /volume .
docker run --rm \
-v myproject_db_data:/volume \
-v $(pwd):/backup \
alpine \
tar czf /backup/db_data.tar.gz -C /volume .
  1. Передать файлы на новый VPS.

На новом сервере

  1. Развернуть проект:
tar -xzf myproject.tar.gz -C /
cd /opt/myproject
  1. Создать volumes:
docker volume create myproject_app_data
docker volume create myproject_db_data
  1. Восстановить данные:
docker run --rm \
-v myproject_app_data:/volume \
-v $(pwd):/backup \
alpine \
sh -c "cd /volume && tar xzf /backup/app_data.tar.gz"
  1. Поднять стек:
docker compose up -d

Почему Compose лучше docker commit

Потому что Compose:

  • воспроизводим;
  • читаем;
  • масштабируем;
  • подходит для CI/CD;
  • позволяет быстро переехать между серверами и хостингами.

Если вы ещё запускаете всё через огромные docker run команды, миграция — отличный момент наконец перевести проект на Compose.

Способ №5. Массовая миграция 50–200+ контейнеров

Вот здесь обычные инструкции из интернета перестают работать.

Если у вас:

  • десятки или сотни клиентских контейнеров;
  • один и тот же Dockerfile / image;
  • разные env, volumes, домены, токены;
  • инфраструктура “мультиклиент” или SaaS;

то переносить всё “по одному контейнеру” — это уже антипаттерн.

В таком сценарии нужно переносить не контейнеры, а систему развёртывания.

Ключевой вопрос

У контейнеров есть уникальные данные?

Если нет, и они отличаются только env-переменными / портами / именами, то переносится:

  • образ;
  • список клиентов;
  • шаблон запуска.

Если да, и у каждого клиента свой volume или папка, то переносится ещё и:

  • volume каждого клиента;
  • bind mount каждого клиента;
  • его метаданные.

Production-подход: “один шаблон + генератор запуска”

Для 200 контейнеров правильная архитектура выглядит так:

Структура

/opt/clients/
client001.env
client002.env
client003.env

Один образ

my-client-app:latest

Один шаблон запуска

docker run -d \
--name client001 \
--restart unless-stopped \
--env-file /opt/clients/client001.env \
-v client001_data:/app/data \
-p 10001:8080 \
my-client-app:latest

И цикл на все контейнеры

while read client; do
docker run -d \
--name $client \
--restart unless-stopped \
--env-file /opt/clients/${client}.env \
-v ${client}_data:/app/data \
my-client-app:latest
done < clients.txt

Что нужно экспортировать при массовой миграции

1. Список контейнеров

docker ps -a --format '{{.Names}}' > containers.txt

2. Конфиги контейнеров

mkdir -p inspect
for c in $(cat containers.txt); do
docker inspect "$c" > "inspect/$c.json"
done

3. Список volumes

docker volume ls --format '{{.Name}}' > volumes.txt

4. Архив всех volumes

mkdir -p volumeswhile read vol; do
echo "Backing up volume: $vol"
docker run --rm \
-v ${vol}:/volume \
-v $(pwd)/volumes:/backup \
alpine \
tar czf /backup/${vol}.tar.gz -C /volume .
done < volumes.txt

5. Список образов

docker ps -a --format '{{.Image}}' | sort | uniq > images.txt

6. Экспорт всех кастомных образов

mkdir -p imageswhile read img; do
safe_name=$(echo "$img" | sed 's/[\/:]/_/g')
docker save "$img" -o "images/${safe_name}.tar"
done < images.txt

Как передать всё на новый сервер

Лучше использовать rsync, а не scp, особенно если переносите много данных:

rsync -avzh --progress /root/docker-migration/ root@NEW_SERVER_IP:/root/docker-migration/

Почему не стоит переносить /var/lib/docker целиком

Иногда встречается “совет” просто скопировать:

/var/lib/docker

Это действительно может сработать, но как основной способ это не рекомендуется, потому что:

  • зависит от версии Docker;
  • зависит от storage driver;
  • может сломаться между разными дистрибутивами и ядрами;
  • переносит вместе с полезными данными ещё и технический мусор.

Такой подход можно рассматривать только как аварийный snapshot, но не как правильную миграцию.

Как мигрировать Docker без потери данных и с минимальным downtime

Для production-проектов главный вопрос не “как скопировать”, а как переехать без потери данных и без долгого простоя.

Вот рабочая схема.

1. Заранее уменьшите TTL DNS

Например, до 300 секунд, чтобы смена IP прошла быстрее.

2. Подготовьте новый VPS заранее

Установите Docker, Compose, проверьте диски, порты, firewall.

3. Сделайте первичную миграцию

Скопируйте:

  • проект;
  • образы;
  • volumes;
  • bind mounts;
  • дампы БД.

4. Не переключайте трафик сразу

Сначала поднимите всё на новом сервере внутренне и проверьте:

  • контейнеры стартуют?
  • приложение отвечает?
  • база на месте?
  • SSL и reverse proxy работают?
  • очереди и cron-задачи живы?

5. Заморозьте запись на старом сервере

На финальном этапе нужно остановить запись в данные.

Варианты:

  • выключить приложение;
  • перевести сайт в maintenance mode;
  • остановить API;
  • остановить контейнеры.

Например:

docker compose down

или точечно:

docker stop app_container
docker stop postgres_container

6. Сделайте финальный “дельта”-бэкап

Потому что между первичной миграцией и финальным cutover данные могли измениться.

Снова:

  • дамп БД;
  • архив volumes;
  • rsync bind mounts.

7. Восстановите финальные данные на новом VPS

И только после этого:

docker compose up -d

8. Переключите DNS / IP / reverse proxy

После проверки — уже боевой cutover.


9. Подержите старый сервер в standby

Не удаляйте его сразу. Лучше оставить на 24–72 часа, чтобы можно было быстро откатиться.


Типичные ошибки при переносе Docker на другой сервер

Вот список того, на чём чаще всего ломаются миграции.


Ошибка №1. Перенесли контейнер, но забыли volume

Это классика.

Сервис запускается, но:

  • база “пустая”;
  • пользовательские файлы пропали;
  • CMS открывается как “свежая установка”.

Причина: был перенесён образ, но не данные.


Ошибка №2. Использовали docker export и ожидали, что всё уедет

Но docker export не включает volumes. Это прямо указано в документации Docker.


Ошибка №3. Не сохранили параметры запуска

Образ загрузился, но контейнер больше не знает:

  • какие порты использовать;
  • где лежат данные;
  • какие env-переменные нужны;
  • как называется сеть.

Решение: хранить запуск в:

  • docker compose.yml,
  • шаблоне docker run,
  • Ansible / deployment scripts.

Ошибка №4. Забыли .env

Контейнер стартует, но приложение падает, потому что не хватает:

  • API-ключей;
  • доменов;
  • токенов;
  • строк подключения к БД.

Ошибка №5. Права доступа и UID/GID

После переноса приложение не может писать в директории.

Например:

chown -R 1000:1000 /opt/myapp/data
chmod -R 755 /opt/myapp/data

Ошибка №6. Порты уже заняты

На новом сервере уже слушают 80, 443, 5432, 6379 и т.д.

Проверка:

ss -tulpn | grep -E ':80|:443|:5432|:6379'

Ошибка №7. SSL / Let’s Encrypt не перенесли

Особенно часто это ломает:

  • Nginx Proxy Manager;
  • Traefik;
  • Caddy.

Нужно переносить не только конфиги, но и:

  • ACME storage;
  • сертификаты;
  • persistent storage reverse proxy.

Какой способ выбрать: рекомендации по сценариям

Теперь самое полезное — какой способ использовать в реальности.


Сценарий 1. Один контейнер без важных данных

Подходит:

  • docker commit
  • docker save
  • docker load

Идеально для:

  • тестового сервиса;
  • временной среды;
  • небольшого self-hosted приложения.

Сценарий 2. Один контейнер с данными

Подходит:

  • docker save / docker load
  • backup volume
  • backup bind mounts

Идеально для:

  • WordPress;
  • Nginx;
  • небольших приложений;
  • админок;
  • CMS.

Сценарий 3. Полноценный стек из нескольких контейнеров

Подходит:

  • Docker Compose
  • backup volumes
  • дампы БД

Это лучший вариант для:

  • production-сайтов;
  • API;
  • SaaS;
  • CRM / ERP;
  • self-hosted платформ.

Сценарий 4. Десятки и сотни контейнеров

Подходит:

  • шаблонный деплой;
  • генерация docker run или Compose;
  • Ansible / CI/CD;
  • централизованный inventory клиентов.

Это лучший вариант для:

  • мультиклиентских платформ;
  • white-label сервисов;
  • hosting-провайдеров;
  • инфраструктур с 50–500 контейнерами.

Сценарий 5. Нужно “перенести всё как есть” максимально быстро

Подходит:

  • snapshot-подход;
  • экспорт образов;
  • архив всех volumes;
  • автоматизированный import.

Использовать только если:

  • важна скорость;
  • нет времени на рефакторинг;
  • потом планируете привести инфраструктуру в порядок.

Вывод

Перенос Docker-контейнеров на другой сервер — задача несложная только в простых кейсах. Как только появляются:

  • volumes,
  • базы данных,
  • reverse proxy,
  • десятки контейнеров,
  • клиентские окружения,

“скопировать контейнер” уже недостаточно.

Короткая рекомендация:

Если у вас:

  • 1–3 контейнера → подойдёт docker save/load + перенос данных;
  • Docker Compose-проект → переносите весь проект и volumes;
  • 50–200+ контейнеров → мигрируйте не контейнеры, а систему развёртывания.

И главное правило:

Правильная Docker-инфраструктура должна не “копироваться”, а “воспроизводиться”.

Если ваш проект можно развернуть на новом сервере из:

  • образа,
  • Compose-файла,
  • .env,
  • volumes / backup,

значит инфраструктура организована правильно — и миграция пройдёт без паники, простоя и ночных “почему всё пустое”.


Нужна помощь с переносом Docker на новый VPS?

Если вы переносите:

  • сайт,
  • CRM,
  • Telegram-ботов,
  • SaaS,
  • 10–200 контейнеров клиентов,
  • или хотите переехать с одного VPS на другой без потери данных,

команда dockerhosting.ru поможет:

  • подготовить новый сервер;
  • перенести Docker-проекты и volumes;
  • настроить reverse proxy, SSL, firewall и бэкапы;
  • минимизировать downtime;
  • привести инфраструктуру в поддерживаемый вид.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *