从Docker容器复制文件到主机的方法
技术背景
在使用Docker进行开发和部署时,有时需要将容器内生成的构建工件复制到主机上。例如,在持续集成(CI)服务器上使用Docker构建依赖项,而不希望在代理服务器上安装所有运行时和库,这就需要将容器内构建的工件复制回主机。
实现步骤
方法一:使用docker cp
命令
这是最直接的方法,可在容器运行或停止时使用。
- 获取容器ID或名称:使用
docker ps -a
命令查看所有容器,获取目标容器的ID或名称。 - 复制文件:使用
docker cp <containerId>:/file/path/within/container /host/path/target
命令复制文件。
1 2
| sudo docker cp goofy_roentgen:/out_read.jpg .
|
方法二:使用docker create
此方法无需启动容器。
- 创建容器:使用
docker create --name dummy IMAGE_NAME
命令创建一个容器。 - 复制文件:使用
docker cp dummy:/path/to/file /dest/to/file
命令复制文件。 - 删除容器:使用
docker rm -f dummy
命令删除容器。
1 2 3
| docker create --name dummy ubuntu docker cp dummy:/etc/hosts ./hosts docker rm -f dummy
|
方法三:挂载卷
通过挂载卷的方式,将容器内的文件复制到主机上。
- 创建目录:在主机上创建一个目录用于存储工件。
- 运行容器并挂载卷:使用
docker run -i -v ${PWD}/artifacts:/artifacts ubuntu:14.04 sh << COMMANDS
命令运行容器并挂载卷。 - 在容器内复制文件:在容器内将工件复制到挂载的卷中。
1 2 3 4 5
| mkdir artifacts docker run -i -v ${PWD}/artifacts:/artifacts ubuntu:14.04 sh << COMMANDS # 构建软件 cp <artifact> /artifacts COMMANDS
|
方法四:使用BuildKit的--output
选项(Docker 19.03及以上版本)
此方法可跳过创建容器和构建镜像的步骤。
- 构建:使用
DOCKER_BUILDKIT=1 docker build --target artifact --output type=local,dest=. .
命令构建并将结果输出到本地目录。
1
| DOCKER_BUILDKIT=1 docker build --target artifact --output type=local,dest=. .
|
核心代码
使用docker cp
1
| docker cp <containerId>:/file/path/within/container /host/path/target
|
使用docker create
1 2 3
| docker create --name dummy IMAGE_NAME docker cp dummy:/path/to/file /dest/to/file docker rm -f dummy
|
挂载卷
1 2 3 4 5
| mkdir artifacts docker run -i -v ${PWD}/artifacts:/artifacts ubuntu:14.04 sh << COMMANDS # 构建软件 cp <artifact> /artifacts COMMANDS
|
使用BuildKit的--output
选项
1
| DOCKER_BUILDKIT=1 docker build --target artifact --output type=local,dest=. .
|
最佳实践
- 权限问题:在使用挂载卷的方法时,可能会遇到文件权限问题。可以使用
chown
命令调整文件的所有者和组。
1 2 3 4
| docker run -i -v ${PWD}:/working_dir -w /working_dir -u $(id -u) \ ubuntu:14.04 sh << COMMANDS chown -R $(id -u):$(id -g) /working_dir/artifacts COMMANDS
|
- 使用容器名称:使用容器名称而不是ID,可提高命令的可读性和可维护性。
常见问题
- 容器未运行时
docker cp
是否可用:可以,容器不运行时也可以使用docker cp
命令。 - 复制目录时出错:如果复制目录时出现权限问题,可以先将目录复制到
/tmp/
,再从/tmp/
移动到目标位置。
1 2
| docker cp 5f2371a7da7c:/home/euler/mfem/miniapps/navier/3dfoc /tmp/ mv /tmp/3dfoc ~/Downloads/
|