196

我的问题与将文件从容器复制到主机的问题有关;我有一个 Dockerfile,它可以获取依赖项、从源代码编译构建工件并运行可执行文件。我还想复制构建工件(在我的情况下,它是.zipsbt dist'../target/` 生成的,但我认为这个问题也适用于 jar、二进制文件等。

docker cp适用于容器,而不是图像;我是否需要启动一个容器才能从中获取文件?在一个脚本中,我尝试/bin/bash在后台以交互模式运行,将文件复制出来,然后杀死容器,但这似乎很麻烦。有没有更好的办法?

另一方面,我想避免.tar在运行后解压文件docker save $IMAGENAME只是为了取出一个文件(但这似乎是现在最简单,如果最慢的选项)。

我会使用 docker 卷,例如:

docker run -v hostdir:out $IMAGENAME /bin/cp/../blah.zip /out

但我boot2docker在 OSX 中运行,我不知道如何直接写入我的 mac 主机文件系统(读写卷安装在我的 boot2docker VM 中,这意味着我无法轻松共享脚本以blah.zip从图像中提取其他人。想法?

4

10 回答 10

279

要从图像中复制文件,请创建一个临时容器,从中复制文件,然后将其删除:

id=$(docker create image-name)
docker cp $id:path - > local-tar-file
docker rm -v $id
于 2015-07-09T11:51:26.763 回答
92

不幸的是,似乎没有办法直接从 Docker 映像复制文件。您需要先创建一个容器,然后从容器中复制文件。

但是,如果您的图像包含cat命令(并且在许多情况下会这样做),您可以使用单个命令来完成:

docker run --rm --entrypoint cat yourimage  /path/to/file > path/to/destination

如果您的图像不包含cat,只需创建一个容器并使用docker cpIgor 回答中建议的命令。

于 2015-12-04T17:13:16.957 回答
82
docker cp $(docker create --rm registry.example.com/ansible-base:latest):/home/ansible/.ssh/id_rsa ./hacked_ssh_key

想要提供基于纯 docker 功能的单线解决方案(不需要 bash)

编辑:容器甚至不必在此解决方案中运行

编辑2:感谢@Jonathan Dumaine for --rm 所以容器将在之后被删除,我只是从未尝试过,因为从某个地方复制一些已经被上一个命令删除的东西听起来不合逻辑,但我尝试了它并且它有效

于 2019-11-26T16:59:19.407 回答
42

一个更快的选择是将文件从正在运行的容器复制到已安装的卷:

docker run -v $PWD:/opt/mount --rm --entrypoint cp image:version /data/libraries.tgz /opt/mount/libraries.tgz

实际0m0.446s

** 对 **

docker run --rm --entrypoint cat image:version /data/libraries.tgz > libraries.tgz

真正的 0m9.014s

于 2018-03-19T07:33:11.163 回答
18

家长评论已经展示了如何使用cat。您也可以以类似的方式使用tar :

docker run yourimage tar -c -C /my/directory subfolder | tar x
于 2016-11-15T11:29:59.760 回答
8

这个问题的另一个(简短)答案:

docker run -v $PWD:/opt/mount --rm -ti image:version bash -c "cp /source/file /opt/mount/"

更新- 正如@Elytscha Smith所指出的, 这仅在您的图像内置 bash 时才有效

于 2020-01-16T15:06:26.830 回答
3

不是对问题详细信息的直接回答,但一般来说,一旦您提取图像,图像就会存储在您的系统上,它的所有文件也是如此。根据本地 Docker 安装的存储驱动程序,这些文件通常可以在/var/lib/docker/overlay2(需要 root 访问权限)中找到。overlay2应该是当今最常见的存储驱动程序,但路径可能会有所不同。

可以使用$ docker inspect image IMAGE_NAME:TAG查找GraphDriver属性找到与图像关联的图层。
至少在我的本地环境中,以下内容也可以快速查看与图像关联的所有图层:
docker inspect image IMAGE_NAME:TAG | jq ".[0].GraphDriver.Data"

在这些diff目录之一中,可以找到想要的文件。
所以理论上,没有必要创建一个临时容器。Ofc 这个解决方案非常不方便。

于 2021-03-22T17:43:07.680 回答
2

你基本上已经有了最好的解决方案。让容器为您复制文件,然后在完成后自行删除。

这会将文件从 复制/inside/container/到您的计算机/path/to/hostdir/

docker run --rm -v /path/to/hostdir:/mnt/out "$IMAGENAME" /bin/cp -r /inside/container/ /mnt/out/
于 2021-01-11T01:16:46.427 回答
0

我在 MacOS 上使用 boot2docker。我可以向您保证,基于“docker cp”的脚本是可移植的。因为任何命令都在 boot2docker 内中继,但随后二进制流会中继回在您的 mac 上运行的 docker 命令行客户端。因此,来自 docker 客户端的写操作在服务器内部执行并写回正在执行的客户端实例!

我正在与我提供的任何 docker 容器共享 docker 卷的备份脚本,并且我的备份脚本在 linux 和 MacOS 上都使用 boot2docker 进行了测试。备份可以在平台之间轻松交换。基本上我在我的脚本中执行以下命令:

docker run --name=bckp_for_volume --rm --volumes-from jenkins_jenkins_1 -v /Users/github/jenkins/backups:/backup busybox tar cf /backup/JenkinsBackup-2015-07-09-14-26-15.tar /jenkins

运行一个新的 busybox 容器,并使用名称 jenkins_jenkins_1 挂载我的 jenkins 容器的卷。整个卷被写入文件 backups/JenkinsBackup-2015-07-09-14-26-15.tar

我已经在 linux 容器和我的 mac 容器之间移动了档案,没有对备份或恢复脚本进行任何调整。如果这是你想要的,你可以在这里找到整个脚本的教程:blacklabelops/jenkins

于 2015-07-09T12:30:56.343 回答
0

您可以将主机上的本地路径绑定cp到容器上的路径,然后将所需文件绑定到脚本末尾的该路径。

$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  nginx:latest

那么之后就不需要复制了。

于 2019-07-23T12:58:14.313 回答