在 Docker 部署中,我们经常面临服务器迁移的需求。如果只是简单的 cp 文件夹,往往会遗漏存储在 Docker 命名卷中的数据库和网站核心文件

在【源服务器】打包数据

停止容器

为了保证数据一致性(特别是数据库),必须先停止服务

1
[root@harbor ~]# docker-compose -f docker.yml down

确认卷名称

Docker Compose 默认会以“目录名_卷名”的格式创建卷

1
2
3
4
[root@harbor ~]# docker volume ls
DRIVER VOLUME NAME
local root_db
local root_wordpress

打包命名卷数据

利用一个临时的 alpine 容器,把卷挂载进去,然后打包成 .tar 文件放到当前目录

打包数据库卷

1
2
3
4
[root@harbor backup]# docker run --rm \
> -v root_db:/volume_data \
> -v $(pwd):/backup \
> registry.cn-hangzhou.aliyuncs.com/jiangxuliu/dockerhub:alpine-clear tar cvf /backup/db_data.tar -C /volume_data .

打包网站卷

1
2
3
4
[root@harbor backup]# docker run --rm \
> -v root_wordpress:/volume_data \
> -v $(pwd):/backup \
> registry.cn-hangzhou.aliyuncs.com/jiangxuliu/dockerhub:alpine-clear tar cvf /backup/root_wordpress.tar -C /volume_data .

执行完成后宿主机当前目录下会存在两个压缩文件

1
2
[root@harbor backup]# ls
db_data.tar root_wordpress.tar
参数 含义 说明
docker run 启动一个新的容器
- - rm 用完即焚 任务执行完(打包完)后,自动删除这个临时容器
- - v root_db:/volume_data 把宿主机的数据卷 root_db,挂载到容器内部的 /volume_data 目录 让临时容器能读取到数据库里的真实文件
- - v $(pwd):/backup $(pwd) 代表宿主机当前所在的目录。把它挂载到容器内部的 /backup 目录 容器里生成的压缩包,放到 /backup 里,就会直接出现在你宿主机的当前目录下
alpine 指定使用的镜像 Alpine 是一个只有 5MB 大小的极简 Linux 系统。下载快,启动快,且自带 tar 工具
tar cvf /backup/db_data.tar -C /volume_data . 新容器启动后执行的命令 tar cvf: 创建压缩归档文件
/backup/db_data.tar: 结果存放宿主机当前目录
-C /volume_data: 告诉 tar 命令,“先切换到 /volume_data 目录”。这样打包的文件结构干净
. : 代表打包该目录下的所有内容

传输文件到【目标服务器】

1
[root@harbor backup]# scp db_data.tar  root_wordpress.tar  root@10.1.74.24:~/

在【目标服务器】恢复数据

初始化卷

先运行一次容器,让 Docker 自动创建出新的空卷,然后立刻停止

1
2
3
4
5
6
[root@harbor ~]# docker-compose -f docker.yml up -d

# 确认卷已创建 (此时是空的)
[root@harbor ~]# docker volume ls

[root@harbor ~]# docker-compose -f docker.yml down

解压恢复数据

将刚才传输过来的 .tar 包,解压到新创建的卷里

恢复数据库

1
2
3
4
[root@harbor backup]# docker run --rm \
> -v root_db:/volume_data \
> -v $(pwd):/backup \
> registry.cn-hangzhou.aliyuncs.com/jiangxuliu/dockerhub:alpine-clear sh -c "rm -rf /volume_data/* && tar xvf /backup/db_data.tar -C /volume_data"

恢复网站

1
2
3
4
[root@harbor backup]# docker run --rm \
> -v root_wordpress:/volume_data \
> -v $(pwd):/backup \
> registry.cn-hangzhou.aliyuncs.com/jiangxuliu/dockerhub:alpine-clear sh -c "rm -rf /volume_data/* && tar xvf /backup/html_data.tar -C /volume_data"
参数 含义
-v myweb_db:/volume_data 挂载新机器上的空卷
sh -c “…” 让 Alpine 执行一段复杂的 Shell 脚本。因为我们要执行两个动作(先清空,再解压)
rm -rf /volume_data/* 清空卷里的所有内容,为了防止旧数据和新初始化的数据冲突,必须先清空确保卷干净
&& 前面的命令成功后,再执行后面的
tar xvf /backup/db_data.tar -C /volume_data 从 /backup (宿主机目录) 读取压缩包,解压到 /volume_data (数据卷) 里

暴力复制

你可能会问:“直接找到 Docker 在 Linux 上的存储目录 /var/lib/docker/volumes/... 然后用 cp 命令复制不行吗?”

  • 可以但不推荐
  1. 跨平台/版本兼容性:如果你的 Docker 版本不同,或者操作系统不同,存储路径可能不一样。用 docker run -v 是 Docker 的标准接口,无论底层怎么变,这个命令永远通用
  2. 权限问题: 数据库文件通常属于 mysql 用户,WordPress 文件属于 www-data 用户。如果你直接用 cp,很容易把文件所有者变成 root,导致新机器启动时报错 “Permission Denied”。

使用 tar 的好处: tar 命令会保留文件的原始权限和所有者信息。打包时是谁的,解压出来还是谁的,完美避坑