Docker -如何将文件从镜像复制到主机?

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

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

另一方面,我希望避免在运行docker save $IMAGENAME后解包.tar文件,只是为了取出一个文件(但这似乎是目前最简单的,但也是最慢的选项)。

我会使用docker卷,例如:

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

但是我在OSX中运行boot2docker,我不知道如何直接写入我的mac主机文件系统(读写卷挂载在我的boot2docker虚拟机内,这意味着我不能轻松地与他人共享从映像中提取blah.zip的脚本。想法吗?

144826 次浏览

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

id=$(docker create image-name)
docker cp $id:path - > local-tar-file
docker rm -v $id

我在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 /詹金斯

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

然而,如果你的图像包含cat命令(在很多情况下都是这样),你可以用一个命令来完成:

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

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

父注释已经展示了如何使用。你也可以以类似的方式使用焦油:

docker run yourimage tar -c -C /my/directory subfolder | tar x

一个更快的选择是将文件从运行的容器复制到挂载的卷:

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

真正的0 m0.446s

** vs **

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

真正的0 m9.014s

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

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

这样以后就没有必要再抄了。

docker cp $(docker create --name tc registry.example.com/ansible-base:latest):/home/ansible/.ssh/id_rsa ./hacked_ssh_key && docker rm tc

希望提供基于纯docker功能的一行解决方案(不需要bash)

编辑:容器甚至不需要在这个解决方案中运行

edit2:感谢@Jonathan Dumaine的——rm,所以容器将被删除后,我只是从来没有尝试过,因为它听起来不合逻辑,从某个地方复制的东西已经被前一个命令删除,但我尝试过,它工作

edit3:由于注释我们发现——rm没有像预期的那样工作,它不会删除容器,因为它从来没有运行过,所以我添加了删除创建的容器的功能(——name tc=temporary-container)

编辑4:出现了这个错误,似乎是docker中的一个错误,因为t在a-z中,而这在几个月前没有发生。

Error response from daemon: Invalid container name (t), only [a-zA-Z0-9][a-zA-Z0-9_.-] are allowed

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

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

更新 -由@Elytscha史密斯 这仅在映像内置bash时有效指出

你已经得到了最佳解。让容器为您复制文件,然后在完成时删除自己。

这将把文件从/inside/container/复制到你的机器/path/to/hostdir/

docker run --rm -v /path/to/hostdir:/mnt/out "$IMAGENAME" /bin/cp -r /inside/container/ /mnt/out/

不是对问题细节的直接回答,但一般来说,一旦你拉了一张图像,映像和它的所有文件都存储在您的系统中. c。根据本地Docker安装的存储驱动程序,这些文件通常可以在/var/lib/docker/overlay2中找到(需要root访问)。overlay2应该是当今最常见的存储驱动程序,但路径可能不同。

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

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

第一个使用docker pull的docker映像

docker pull <IMG>:<TAG>

然后使用docker create命令创建一个容器,并将容器id存储为一个变量

img_id=$(docker create <IMG>:<TAG>)

现在,运行docker cp命令将文件夹和文件从docker容器复制到主机

docker cp $img_id:/path/in/container /path/in/host

一旦文件/文件夹被移动,使用docker rm删除容器

docker rm -v $img_id

Igor Bukanov回答的PowerShell变体:

$id = & docker create image-name
docker cp ${id}:path - > local-file.tar
docker rm -v $id