Docker 全量备份恢复实战:可离线、可迁移、可复原的标准方案

在日常运维里,Docker 的"导入导出"需求非常常见,通常集中在以下几类场景:

  • 需要对服务做一次 全量备份
  • 需要在新机器上做 完整恢复
  • 目标机器不能联网,要做 离线迁移
  • 需要把某个容器、镜像、数据卷打包后带到另一台服务器
  • 需要在升级、迁移、重装系统前保留业务状态

但很多人第一次接触时,很容易把下面几组命令混淆:

  • docker save / docker load
  • docker export / docker import
  • docker cp
  • docker volume
  • docker compose

这篇文章的目标不是罗列命令,而是用 Cookbook 的方式告诉你:

面对具体场景时,到底该用哪一组命令。


先说结论:Docker 的"完整迁移"到底要备份什么

如果你要迁移的是一个"可运行的服务",而不是一个临时容器快照,那么完整备份通常应包括以下 3 类内容:

  • 镜像
  • 编排与配置
  • 数据

对应到 Docker 世界里,就是:

  • 镜像docker save / docker load
  • 编排与配置compose.yaml.env、配置文件目录
  • 数据:named volume 或 bind mount 的真实数据目录

所以最推荐的全量方案其实是:

  1. 导出镜像
  2. 备份 Compose 文件和配置
  3. 打包 Volume 或宿主机挂载目录
  4. 在目标机器上恢复镜像、配置和数据
  5. 再用 Compose 拉起服务

一句话总结:

不要把"导出一个容器"误认为"完整备份一个 Docker 服务"。


一张表看懂:到底该用哪个命令

目标 推荐命令 是否包含 Volume 数据 是否适合服务迁移
导出镜像 docker save
导入镜像 docker load
导出容器文件系统 docker export
导入为镜像 docker import
复制单个文件 docker cp 部分 辅助用途
备份 named volume docker run -v volume:/data ... tar
备份 bind mount tar 宿主机目录

核心概念:save/load 和 export/import 到底有什么区别

这是最容易混淆的一组。

docker save / docker load

这组命令用于 镜像级别 的导出导入。

适用场景

  • 离线传输镜像
  • 内网环境部署
  • 多台机器之间复制镜像
  • 不能访问公网镜像仓库时分发镜像

特点

  • 保留镜像层信息
  • 保留 tag
  • 适合正式迁移和离线部署
  • 不包含容器运行状态
  • 不包含 volume 数据

示例:

bash 复制代码
docker save -o nginx.tar nginx:latest
docker load -i nginx.tar

docker export / docker import

这组命令用于 容器文件系统快照 的导出导入。

适用场景

  • 临时导出某个容器当前文件系统内容
  • 制作一个简单的新镜像基底
  • 调试、留档、分析

特点

  • 导出的是容器当前文件系统
  • 不保留镜像历史层
  • 不保留 Compose 配置
  • 不保留 volume 数据
  • 不适合完整迁移服务

示例:

bash 复制代码
docker export my-container -o my-container.tar
cat my-container.tar | docker import - my-image:latest

最重要的结论

如果你的目的是"离线迁移服务"或"完整备份恢复",优先使用 save/load,而不是 export/import


Recipe 1:离线导出和导入镜像

这是最常见的一道"配方"。

场景

目标服务器不能联网,但需要运行某个镜像。

导出镜像

bash 复制代码
docker pull nginx:1.27
docker save -o nginx-1.27.tar nginx:1.27

如果要压缩:

bash 复制代码
gzip nginx-1.27.tar

得到:

bash 复制代码
nginx-1.27.tar.gz

传输到目标机器

可以使用:

  • scp
  • rsync
  • U 盘
  • 内部文件分发系统

例如:

bash 复制代码
scp nginx-1.27.tar.gz user@target:/opt/

目标机器导入

bash 复制代码
gunzip /opt/nginx-1.27.tar.gz
docker load -i /opt/nginx-1.27.tar

验证

bash 复制代码
docker images

Recipe 2:一次导出多个镜像

场景

一个服务栈包含多个镜像,例如:

  • nginx
  • redis
  • mysql
  • myapp

导出

bash 复制代码
docker save -o app-stack.tar \
  nginx:1.27 \
  redis:7 \
  mysql:8 \
  myapp:1.0

导入

bash 复制代码
docker load -i app-stack.tar

建议

如果你是在做一套离线交付包,推荐统一放到一个目录中:

bash 复制代码
backup_bundle/
├── images/
│   └── app-stack.tar
├── config/
│   ├── compose.yaml
│   └── .env
└── volumes/

这样最清晰。


Recipe 3:导出容器文件系统,但不用于服务迁移

场景

想保留当前容器内部改动,或者分析容器现状。

导出

bash 复制代码
docker export my-container -o my-container.tar

导入为镜像

bash 复制代码
cat my-container.tar | docker import - my-container-snapshot:latest

什么时候可以用

可以用于:

  • 保存实验环境
  • 导出某次调试后的临时系统状态
  • 生成一个轻量新镜像

什么时候不要用

不要用于:

  • 完整备份业务服务
  • 恢复数据库服务
  • 迁移含 volume 的应用
  • 替代 Compose 部署

因为它 不包含 volume 数据,也不保留运行编排信息


Recipe 4:完整备份一个 Compose 服务

这是最实用、也最值得收藏的一道"配方"。

场景

你有一个通过 Docker Compose 运行的服务,需要:

  • 全量备份
  • 异机恢复
  • 离线迁移
  • 重装系统前保留所有业务内容

备份对象

完整备份至少包括:

  • compose.yaml
  • .env
  • 应用配置文件
  • 镜像
  • volume 数据

第一步:准备备份目录

bash 复制代码
mkdir -p backup_bundle/{images,config,volumes}

第二步:备份 Compose 文件和配置

bash 复制代码
cp compose.yaml backup_bundle/config/
[ -f .env ] && cp .env backup_bundle/config/

如果还有配置目录,例如:

bash 复制代码
cp -r ./config backup_bundle/config/

第三步:导出镜像

先找出 Compose 使用的镜像:

bash 复制代码
docker compose config

然后导出镜像:

bash 复制代码
docker save -o backup_bundle/images/app-images.tar \
  nginx:1.27 \
  redis:7 \
  mysql:8 \
  myapp:1.0

第四步:备份 named volume

为什么 volume 要单独备份

因为:

  • docker save 不包含 volume
  • docker export 也不包含 volume

数据卷必须自己单独打包。

查看 volume 列表

bash 复制代码
docker volume ls

备份某个 volume

bash 复制代码
docker run --rm \
  -v myproj_mysql_data:/data \
  -v $(pwd)/backup_bundle/volumes:/backup \
  alpine \
  tar czf /backup/mysql_data.tar.gz -C /data .

再比如 Redis 数据:

bash 复制代码
docker run --rm \
  -v myproj_redis_data:/data \
  -v $(pwd)/backup_bundle/volumes:/backup \
  alpine \
  tar czf /backup/redis_data.tar.gz -C /data .

第五步:建议停服务后再做最终备份

如果应用正在写数据,备份出的数据可能不一致。

特别是以下类型服务:

  • MySQL
  • PostgreSQL
  • Redis
  • MongoDB
  • Elasticsearch

推荐在最终备份前执行:

bash 复制代码
docker compose stop

或者:

bash 复制代码
docker compose down

然后再重新执行 volume 打包。

备份完成后再启动:

bash 复制代码
docker compose up -d

Recipe 5:在目标机器上恢复完整服务

场景

你已经拿到了完整备份包,要在新机器恢复服务。

假设备份目录在:

bash 复制代码
/opt/backup_bundle

第一步:导入镜像

bash 复制代码
docker load -i /opt/backup_bundle/images/app-images.tar

第二步:恢复 Compose 文件

bash 复制代码
mkdir -p /opt/myapp
cp /opt/backup_bundle/config/compose.yaml /opt/myapp/
[ -f /opt/backup_bundle/config/.env ] && cp /opt/backup_bundle/config/.env /opt/myapp/

如果有配置目录:

bash 复制代码
cp -r /opt/backup_bundle/config/config /opt/myapp/

第三步:先创建 volume

进入项目目录:

bash 复制代码
cd /opt/myapp
docker compose up -d

这一步的主要目的是让 Docker 把 Compose 中声明的 volume 创建出来。

然后停掉服务,准备恢复数据:

bash 复制代码
docker compose stop

第四步:把备份数据恢复到 volume

恢复 MySQL 数据:

bash 复制代码
docker run --rm \
  -v myapp_mysql_data:/data \
  -v /opt/backup_bundle/volumes:/backup \
  alpine \
  sh -c "cd /data && tar xzf /backup/mysql_data.tar.gz"

恢复 Redis 数据:

bash 复制代码
docker run --rm \
  -v myapp_redis_data:/data \
  -v /opt/backup_bundle/volumes:/backup \
  alpine \
  sh -c "cd /data && tar xzf /backup/redis_data.tar.gz"

第五步:启动服务

bash 复制代码
cd /opt/myapp
docker compose up -d

验证

检查:

  • 容器是否正常启动
  • 端口是否监听
  • 业务是否可访问
  • 数据是否存在
  • 日志是否正常
bash 复制代码
docker compose ps
docker compose logs -f

Recipe 6:如果你使用的是 bind mount,如何备份和恢复

很多服务不是使用 named volume,而是直接挂载宿主机目录,比如:

yaml 复制代码
services:
  app:
    volumes:
      - /data/app:/app/data
      - /data/logs:/app/logs

这种情况下,备份方式反而更简单。

备份

bash 复制代码
tar czf app-bind-data.tar.gz /data/app /data/logs

恢复

bash 复制代码
tar xzf app-bind-data.tar.gz -C /

注意

使用 bind mount 时,完整备份内容就变成:

  • 镜像
  • Compose 文件
  • 宿主机目录数据

而不是 Docker volume 本身。


Recipe 7:如何打包成一个可交付的离线安装包

如果你要把一套服务交付给客户、同事或另一台服务器,推荐把所有内容整理成一个标准目录。

推荐目录结构

bash 复制代码
offline_bundle/
├── images/
│   └── app-images.tar
├── config/
│   ├── compose.yaml
│   ├── .env
│   └── config/
├── volumes/
│   ├── mysql_data.tar.gz
│   └── redis_data.tar.gz
├── scripts/
│   ├── restore.sh
│   └── backup.sh
└── README.md

打包

bash 复制代码
tar czf offline_bundle.tar.gz offline_bundle

恢复时

只需:

  1. 解压
  2. 导入镜像
  3. 恢复配置
  4. 创建 volume
  5. 导入 volume 数据
  6. 启动服务

这是很适合企业内网、机房隔离区、生产环境交付的方式。


Recipe 8:用脚本实现一键备份

下面给一个通用思路的备份脚本模板。

bash 复制代码
#!/usr/bin/env bash
set -euo pipefail

PROJECT_DIR=/opt/myapp
BACKUP_DIR=/opt/backup_bundle

mkdir -p "$BACKUP_DIR/images" "$BACKUP_DIR/config" "$BACKUP_DIR/volumes"

cd "$PROJECT_DIR"

echo "==> 备份配置"
cp compose.yaml "$BACKUP_DIR/config/" || true
[ -f .env ] && cp .env "$BACKUP_DIR/config/" || true
[ -d config ] && cp -r config "$BACKUP_DIR/config/" || true

echo "==> 停止服务"
docker compose stop

echo "==> 导出镜像"
docker save -o "$BACKUP_DIR/images/app-images.tar" \
  nginx:1.27 redis:7 mysql:8 myapp:1.0

echo "==> 导出 volumes"
docker run --rm \
  -v myapp_mysql_data:/data \
  -v "$BACKUP_DIR/volumes":/backup \
  alpine \
  tar czf /backup/mysql_data.tar.gz -C /data .

docker run --rm \
  -v myapp_redis_data:/data \
  -v "$BACKUP_DIR/volumes":/backup \
  alpine \
  tar czf /backup/redis_data.tar.gz -C /data .

echo "==> 启动服务"
docker compose up -d

echo "备份完成:$BACKUP_DIR"

Recipe 9:用脚本实现一键恢复

bash 复制代码
#!/usr/bin/env bash
set -euo pipefail

PROJECT_DIR=/opt/myapp
BACKUP_DIR=/opt/backup_bundle

mkdir -p "$PROJECT_DIR"

cp "$BACKUP_DIR/config/compose.yaml" "$PROJECT_DIR/" || true
[ -f "$BACKUP_DIR/config/.env" ] && cp "$BACKUP_DIR/config/.env" "$PROJECT_DIR/" || true
[ -d "$BACKUP_DIR/config/config" ] && cp -r "$BACKUP_DIR/config/config" "$PROJECT_DIR/" || true

echo "==> 导入镜像"
docker load -i "$BACKUP_DIR/images/app-images.tar"

cd "$PROJECT_DIR"

echo "==> 创建 volumes"
docker compose up -d
docker compose stop

echo "==> 恢复数据"
docker run --rm \
  -v myapp_mysql_data:/data \
  -v "$BACKUP_DIR/volumes":/backup \
  alpine \
  sh -c "cd /data && tar xzf /backup/mysql_data.tar.gz"

docker run --rm \
  -v myapp_redis_data:/data \
  -v "$BACKUP_DIR/volumes":/backup \
  alpine \
  sh -c "cd /data && tar xzf /backup/redis_data.tar.gz"

echo "==> 启动服务"
docker compose up -d

echo "恢复完成"

Recipe 10:只复制容器里的单个文件

有时候不需要全量备份,只想拿出一个文件,比如日志、配置、证书。

这时可以用 docker cp

从容器拷贝到宿主机

bash 复制代码
docker cp my-container:/etc/nginx/nginx.conf ./nginx.conf

从宿主机拷贝到容器

bash 复制代码
docker cp ./nginx.conf my-container:/etc/nginx/nginx.conf

适用场景

  • 临时导出配置
  • 复制日志
  • 调整证书
  • 小范围修复

不适用

  • 不适合作为完整迁移方案
  • 不适合批量数据备份

常见误区

误区 1:docker export 可以完整迁移服务

不能。

它只导出容器文件系统,不包含:

  • volume 数据
  • Compose 配置
  • 网络声明
  • 环境变量
  • 启动命令的完整上下文

误区 2:docker save 会连数据一起导出

不会。

docker save 只处理镜像,不处理运行时数据卷。


误区 3:docker compose down 会自动删除数据

默认不会。

只有加上 -v 才会删除相关 volume:

bash 复制代码
docker compose down -v

这条命令非常危险,执行前一定确认。


误区 4:直接备份 /var/lib/docker 就行

虽然理论上可以做整机级灾备,但通常不推荐作为常规迁移方案,因为它:

  • 强依赖 Docker 版本
  • 强依赖存储驱动
  • 可移植性差
  • 跨机器恢复失败风险高

常规迁移还是应该采用:

  • 镜像导出
  • 配置保存
  • volume 数据单独打包

这种标准做法。


最佳实践清单

1. 服务迁移优先用 save/load

而不是 export/import

2. Volume 必须单独备份

镜像不等于数据。

3. Compose 文件必须纳入备份

没有编排文件,恢复后的服务往往不可复现。

4. 数据库类服务备份前尽量停写

避免产生不一致数据。

5. 离线交付建议做成统一目录包

镜像、配置、数据、脚本放在一起最利于维护。

6. 恢复流程要提前演练

真正有故障时,第一次恢复往往最容易出错。

7. 给备份包加版本号和日期

例如:

bash 复制代码
backup_bundle_2025-02-16_v1.tar.gz

这样便于追溯。


一套推荐的标准方案

如果你问我:Docker 如何做"全量备份恢复 + 离线迁移"的最佳方案?

我的标准答案是:

标准备份包应包含

  • compose.yaml
  • .env
  • 配置文件目录
  • docker save 导出的镜像包
  • 所有 volume 的压缩归档
  • 备份和恢复脚本
  • 一份 README

标准备份动作

  1. 停止服务或冻结写入
  2. 导出镜像
  3. 打包 volume
  4. 备份 Compose 和配置
  5. 统一归档

标准恢复动作

  1. 导入镜像
  2. 恢复 Compose 和配置
  3. 创建 volume
  4. 恢复 volume 数据
  5. 启动服务
  6. 做健康检查

这套方案的优点是:

  • 可离线
  • 可迁移
  • 可复现
  • 可审计
  • 可脚本化
  • 不依赖原机器环境过深

总结

Docker 的导入导出不能只盯着一个命令看,而应该根据对象来区分:

  • 镜像docker save / docker load
  • 容器文件系统快照docker export / docker import
  • 单个文件docker cp
  • 数据卷tar + 临时容器
  • 服务定义compose.yaml.env、配置目录

如果你的目标是:

  • 全量备份
  • 完整恢复
  • 离线迁移
  • 跨主机部署

那么最稳妥的方式永远是:

镜像 + 配置 + 数据 三者一起备份与恢复。

这才是 Docker 世界里真正意义上的"完整迁移"。

相关推荐
IMPYLH1 小时前
Linux 的 base32 命令
linux·运维·服务器·bash·shell
不知名。。。。。。。。2 小时前
仿muduo库实现高并发服务器---监听描述符Acceptor模块
运维·服务器
CDN3602 小时前
运维笔记|360CDN高防服务器部署教程,抗D+源站防护一站式配置
运维·服务器·笔记
geek_Chen012 小时前
轻量级虚拟机--Docker使用手册
docker·容器
荆楚闲人2 小时前
ubuntu下实现自动以root用户开机无密码方式进入桌面
linux·运维·ubuntu
Insist7533 小时前
Kingbase--单机部署完整流程
运维·数据库
zuoerjinshu3 小时前
Nginx实现接口复制
运维·nginx·junit
陈皮糖..3 小时前
Ansible实战教程----使用Ansible角色源码编译部署nginx服务
linux·运维·nginx·自动化·云计算·ansible