15.5.3 数据卷备份、恢复与迁移

在生产环境中,数据卷的备份、恢复与迁移是保障业务连续性与可迁移性的关键环节。本节围绕常见数据卷类型(volume、bind、tmpfs)给出可落地的方法与注意事项。

1. 备份策略与原则#

  • 一致性优先:对数据库类服务建议在应用层进行快照或停写后备份,避免脏数据。
  • 最小停机:可结合主从复制、只读切换或业务低峰期执行备份。
  • 版本化与校验:备份文件带时间戳与版本号,生成校验和(md5/sha256)。
  • 可恢复性验证:定期进行恢复演练,确保备份可用。

原理草图(Volume 备份链路)

文章图片

2. Volume 数据卷备份#

2.1 使用临时容器备份(tar)#

适用场景:Volume 类型数据卷的离线/轻量备份。

# 查看卷
docker volume ls

# 假设数据卷名为 app_data
# 备份到宿主机 /backup 目录
mkdir -p /backup

docker run --rm \
  -v app_data:/data:ro \
  -v /backup:/backup \
  alpine:3.19 \
  sh -c "tar -czf /backup/app_data_$(date +%F).tar.gz -C /data ."

# 计算校验和
sha256sum /backup/app_data_*.tar.gz > /backup/app_data_$(date +%F).sha256

命令解释
- -v app_data:/data:ro:以只读挂载数据卷,避免备份时写入。
- -C /data .:打包数据目录内容而非包含目录本身。

2.2 使用 rsync 备份(增量)#

适用场景:数据量大、需要增量同步。

# 安装 rsync(宿主机)
# Ubuntu/Debian
sudo apt-get update && sudo apt-get install -y rsync

# 备份到本地目录 /backup/app_data/
mkdir -p /backup/app_data

docker run --rm \
  -v app_data:/data:ro \
  -v /backup/app_data:/backup \
  alpine:3.19 \
  sh -c "apk add --no-cache rsync && rsync -av --delete /data/ /backup/"

3. Volume 数据卷恢复#

3.1 恢复到同名数据卷#

# 确保目标卷存在
docker volume create app_data

# 将备份恢复到卷
docker run --rm \
  -v app_data:/data \
  -v /backup:/backup \
  alpine:3.19 \
  sh -c "tar -xzf /backup/app_data_2024-01-01.tar.gz -C /data"

# 验证卷内容
docker run --rm -v app_data:/data alpine:3.19 ls -al /data

3.2 恢复到新数据卷(迁移或回滚)#

# 创建新卷
docker volume create app_data_new

# 恢复到新卷
docker run --rm \
  -v app_data_new:/data \
  -v /backup:/backup \
  alpine:3.19 \
  sh -c "tar -xzf /backup/app_data_2024-01-01.tar.gz -C /data"

4. Bind Mount 备份与迁移#

适用场景:数据直接存在宿主机路径(如 /data/app)。

# 停止容器,保证一致性
docker stop app

# 备份 bind 目录
tar -czf /backup/app_bind_$(date +%F).tar.gz -C /data/app .

# 恢复到新主机(示例)
# 1) 将备份包传输到新主机
# 2) 解压到目标目录
mkdir -p /data/app
tar -xzf /backup/app_bind_2024-01-01.tar.gz -C /data/app

# 启动容器并重新挂载
docker run -d --name app \
  -v /data/app:/app/data \
  your_image:latest

命令解释
- -C /data/app .:只打包目录内容,避免多一层路径。

5. tmpfs 数据备份注意事项#

tmpfs 是内存数据,容器重启即失效。若必须备份:

# 以临时容器读取 tmpfs(仅运行时可访问)
docker run --rm \
  --tmpfs /cache \
  alpine:3.19 sh -c "echo 'temp' > /cache/a.txt"

# 将 tmpfs 内容复制到宿主机目录(容器运行期间)
docker run --rm \
  --tmpfs /cache \
  -v /backup:/backup \
  alpine:3.19 sh -c "echo 'temp' > /cache/a.txt && tar -czf /backup/tmpfs_$(date +%F).tar.gz -C /cache ."

建议:重要数据不要放在 tmpfs;仅缓存类可用。

6. 跨主机迁移方案#

6.1 备份文件迁移(scp/rsync)#

# 本机生成备份
tar -czf /backup/app_data_$(date +%F).tar.gz -C /var/lib/docker/volumes/app_data/_data .

# 迁移到新主机
scp /backup/app_data_2024-01-01.tar.gz user@new-host:/backup/

# 新主机恢复
docker volume create app_data
docker run --rm \
  -v app_data:/data \
  -v /backup:/backup \
  alpine:3.19 \
  sh -c "tar -xzf /backup/app_data_2024-01-01.tar.gz -C /data"

6.2 在线迁移(rsync over ssh)#

# 在源主机执行(示例)
rsync -avz --delete \
  /var/lib/docker/volumes/app_data/_data/ \
  user@new-host:/var/lib/docker/volumes/app_data/_data/

7. 故障排查#

  • 恢复后数据为空
  • 检查 tar 解压路径是否正确:-C /data 是否指向卷挂载目录。
  • 使用 docker volume inspect app_data 查看真实路径。
  • 权限问题
  • 对应服务用户检查 UID/GID:ls -ln /data
  • 修复:chown -R 1000:1000 /data(按实际 UID/GID)。
  • 备份文件损坏
  • 校验:sha256sum -c app_data_2024-01-01.sha256
  • 容器写入中导致数据不一致
  • 建议停容器或使用应用级快照(如 MySQL FLUSH TABLES WITH READ LOCK)。

8. 练习#

  1. 创建一个 Volume 并写入测试文件,然后使用临时容器备份与恢复。
  2. 将 Volume 备份包迁移到另一台主机并恢复,验证文件一致性。
  3. 使用 rsync 做一次增量备份,观察 --delete 的效果。
  4. 模拟权限问题,尝试恢复后修复 UID/GID。