使用 Docker 时,常常需要备份存储在卷中的数据,或者为了测试而复制到另一个卷。
虽然可以简单地想到 docker cp 命令,但该命令仅支持在容器的文件系统和主机之间进行复制,而无法直接访问 Docker 管理的卷。
本文将介绍复制 Docker 卷的正确方法,我们将重点关注‘为何’要使用这种方式的原理。理解这个原理后,您可以在需要时自然地应用,而无需记住命令。
核心原理很简单。
操作 Docker 卷的最安全且‘道地’的方法就是利用可以访问该卷的‘临时容器’进行桥接。
1. 将现有卷复制到新卷 (卷到卷)
这是最常见的场景。您可能想将正在运行的 db_data 卷复制到测试用的 db_data_test 卷。
🤔 为什么要使用临时容器?
Docker 卷存储在主机文件系统的某个地方(如 /var/lib/docker/volumes/...),但由 Docker 守护进程管理。直接访问该路径并使用 cp 命令并不推荐,因为这可能导致权限问题或数据一致性问题。
相反,我们将运行一个同时挂载两个卷的临时容器。
-
容器将源卷(
source_volume)挂载到/from路径。 -
容器将目标卷(
new_volume)挂载到/to路径。 -
容器一启动,就会执行一个简单的 Linux 命令(
cp或tar),将/from的所有数据复制到/to。 -
命令完成后,容器会自动销毁(
--rm选项)。
这个容器仅作为数据复制的'工具'。
🚀 如何:命令示例
将 source_data 卷的数据复制到 target_data 卷的示例。
- 创建测试用卷(可选)
docker volume create source_data
docker volume create target_data
# (假设 source_data 中已有数据。)
- 通过临时容器进行复制
docker run --rm \
-v source_data:/from \
-v target_data:/to \
alpine \
sh -c "cp -a /from/. /to/"
💡 命令解说
-
docker run --rm:--rm标志表示在容器完成操作并退出时立即删除容器。这是临时操作的必要条件。 -
-v source_data:/from: 将source_data卷挂载到容器内的/from目录。 -
-v target_data:/to: 将target_data卷挂载到容器内的/to目录。 -
alpine: 使用体积非常小的alpineLinux 镜像,其中包含基本的实用程序如cp或sh。 -
sh -c "...": 在 alpine 容器运行时要执行的命令。 -
cp -a /from/. /to/:-
-a(归档): 这个标志是关键。它不仅仅是简单复制(cp -r),而是保留所有属性,如所有权、权限、时间戳等。在处理数据库文件等敏感数据时,这一点非常重要。 -
/from/.: 这表示的是/from内部的所有内容(包括隐藏文件),而不是/from目录本身。
-
2. 将卷数据复制到主机文件系统(备份)
当您希望将卷的数据备份到本地机器或服务器的特定目录中(如 .tar 文件)时,可以使用此方法。
🤔 为什么:它是如何工作的?
原理与第一个相同。只不过目标从‘Docker 卷’变为‘主机目录’。
Docker 支持将主机的特定目录挂载到容器中的绑定挂载(Bind Mount)功能。
-
容器将源卷(
source_volume)挂载到/data路径。 -
容器将主机的特定目录(
$(pwd)/backup)挂载到/backup路径。 -
容器将
/data的内容复制(或压缩)到/backup目录。 -
这个操作是在容器内部完成的,但由于
/backup与实际的主机目录是连接的,因此结果会保留在主机中。
🚀 如何:命令示例
将 source_data 卷的数据复制到当前路径($(pwd))的 backup 目录中。
# 在主机上创建用于备份的目录
mkdir -p $(pwd)/backup
docker run --rm \
-v source_data:/data:ro \
-v $(pwd)/backup:/backup \
alpine \
cp -a /data/. /backup/
💡 命令解说
-
-v source_data:/data:ro: 添加了:ro(只读)标志。备份时仅需读取数据,因此最好以只读方式挂载以防止意外修改原始卷。 -
-v $(pwd)/backup:/backup: 与source_data(卷名)不同,以/开头或包含$(pwd)(当前路径)的绝对/相对路径指的是主机的目录。
3. 关键复制技巧(Tips)
技巧 1: 使用 tar 进行高效复制(压缩备份)
使用 tar 而不是 cp 命令有多个好处。特别是在将数据打包为存档文件(.tar.gz)进行备份时非常有用。
卷到卷(使用 tar)
可能比 cp 更快,特别是在文件较多时更有效。
docker run --rm \
-v source_data:/from \
-v target_data:/to \
alpine \
sh -c "cd /from && tar -cf - . | (cd /to && tar -xf -)"
-
cd /from && tar -cf - .: 先转到/from,然后将当前目录(.)的内容打包为(c)而不是文件(f),结果发往标准输出(-)。 -
| (cd /to && tar -xf -): 通过管道(|)接收标准输出,并在/to目录中解压(x)。
卷到主机(压缩备份)
将 source_data 卷的内容压缩为 backup.tar.gz 文件并存储在主机上。
docker run --rm \
-v source_data:/data:ro \
-v $(pwd):/backup \
alpine \
tar -czf /backup/backup.tar.gz -C /data .
-
tar -czf /backup/backup.tar.gz ...: 创建(c),进行 gzip 压缩(z),并生成文件(f)/backup/backup.tar.gz。 -
-C /data .: 这一部分很重要。先转到 /data 目录,再压缩其中所有内容(.
)这样做是为了确保 tar 文件中不会包含多余的 /data 路径。
技巧 2: 从主机文件恢复到卷
与备份相反,恢复也使用相同的原理。只需改变 cp 的方向即可。
# 将 $(pwd)/backup 目录的数据恢复到 new_data 卷
docker run --rm \
-v new_data:/data \
-v $(pwd)/backup:/backup:ro \
alpine \
cp -a /backup/. /data/
总结
操作 Docker 卷的关键在于“将容器作为工具使用”的思维方式。必要时,通过运行挂载需要的卷和目录的临时容器,安全地执行 cp 或 tar 等标准 Linux 命令,而不是直接操作主机中的卷文件。
只要记住这个原理,您就能在任何情况下自由复制、备份和恢复卷数据。
目前没有评论。