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

时间:2014-08-13 17:09:44

标签: docker boot2docker

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

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

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

我会使用泊坞窗卷,例如:

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

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

10 个答案:

答案 0 :(得分:96)

回答旧问题以供参考。要从映像复制文件,请创建一个临时容器,从中复制该文件,然后将其删除:

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

答案 1 :(得分:36)

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

但是,如果您的图像包含cat命令(在许多情况下它会执行),您可以使用一个命令执行此操作:

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

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

答案 2 :(得分:13)

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

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

真实0m0.446s

VS

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

真实的0m9.014s

答案 3 :(得分:9)

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

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

答案 4 :(得分:4)

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

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

更新-如@Elytscha Smith所述,仅当您的图像内置bash时,此功能才有效

答案 5 :(得分:1)

不是对问题详细信息的直接回答,但一般来说,一旦您提取图像,图像就会存储在您的系统中,其所有文件也是如此。根据本地 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这个解决方案很不方便。

答案 6 :(得分: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

答案 7 :(得分:0)

您可以bind主机上的本地路径到容器上的路径,然后cp在脚本末尾$ docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/target,target=/app \ nginx:latest 到该路径。

custom_objects

然后无需再复制。

答案 8 :(得分:0)

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

希望提供一线解决方案

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

答案 9 :(得分:0)

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

这会将文件从 If ThisWorkbook.Sheets("Sheet1").Range("C41").Value = "prime-membership" Then IE.Document.getElementById("prime-membership").Checked = True Else IE.Document.getElementById("non-prime-membership").Checked = True End If 复制到您位于 /inside/container/ 的机器上。

/path/to/hostdir/