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

Mar*_*ark 77 docker boot2docker

我的问题与将文件从容器复制到主机的问题有关; 我有一个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
Run Code Online (Sandbox Code Playgroud)

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

Igo*_*nov 126

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

id=$(docker create image-name)
docker cp $id:path - > local-tar-file
docker rm -v $id
Run Code Online (Sandbox Code Playgroud)

  • 有什么理由复制到标准输出然后将其定向到本地文件?当我这样做时,它在文件内容之前和之后转储了一堆控制字符。直接作为“docker cp $id:path > local-tar-file”运行它效果很好。 (3认同)
  • @Yonatan 保存为 tar 存档的主要原因是为了确保提取包括所有权名称在内的所有信息,并允许在提取存档之前在本地检查存档以提高安全性。另外,早期的 docker 版本 IIRC 不支持将目录从容器复制到本地目录,或者存在一些问题。但是,如果您知道容器的结构并且您的 docker 版本不是古老的版本,那么您当然可以使用 docker cp $id:path local_path 来提取到本地文件或目录。 (3认同)
  • @ThorSummoner"docker create"在docker 1.3中引入,https://blog.docker.com/2014/10/docker-1-3-signed-images-process-injection-security-options-mac-shared-directories/ (2认同)
  • @ChrisCleeland当您向 docker create 命令添加 `--entrypoint /` 参数时,它在您的情况下有效吗? (2认同)

Ely*_*ith 52

docker cp $(docker create --rm registry.example.com/ansible-base:latest):/home/ansible/.ssh/id_rsa ./hacked_ssh_key
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 被低估的答案!如果您将“--rm”添加到“docker create”调用中以不留下临时容器的痕迹,它也可以工作。 (4认同)
  • 我认为“--rm”在这种情况下不会删除任何内容,因为容器永远不会运行 (4认同)
  • 不,因为正如 roman 所说, --rm 不会删除任何内容,因为容器永远不会运行 (3认同)
  • 随后必须调用“docker rm”来删除容器。 (2认同)

fon*_*ons 46

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

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

docker run --rm --entrypoint cat yourimage  /path/to/file > path/to/destination
Run Code Online (Sandbox Code Playgroud)

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

  • 很棒的解决方案。无法访问我的容器,因为它在启动后一秒钟崩溃,但需要在其中获取一个文件。这工作得很好。 (2认同)

Mik*_*kko 16

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

docker run -v $PWD:/opt/mount --rm --entrypoint cp image:version /data/libraries.tgz /opt/mount/libraries.tgz
Run Code Online (Sandbox Code Playgroud)

真正的0m0.446s

VS

docker run --rm --entrypoint cat image:version /data/libraries.tgz > libraries.tgz
Run Code Online (Sandbox Code Playgroud)

真正的0m9.014s


wed*_*oft 11

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

docker run yourimage tar -c -C /my/directory subfolder | tar x
Run Code Online (Sandbox Code Playgroud)

  • 实际上,我使用`docker run --rm --entrypoint tar _image_ cC _img_directory_.| tar xvC _host_directory_` (4认同)

Sad*_*ula 9

首先使用 docker pull 拉取 docker 镜像

docker pull <IMG>:<TAG>
Run Code Online (Sandbox Code Playgroud)

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

img_id=$(docker create <IMG>:<TAG>)
Run Code Online (Sandbox Code Playgroud)

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

docker cp $img_id:/path/in/container /path/in/host
Run Code Online (Sandbox Code Playgroud)

移动文件/文件夹后,使用 docker rm 删除容器

docker rm -v $img_id
Run Code Online (Sandbox Code Playgroud)


fre*_*dev 6

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

docker run -v $PWD:/opt/mount --rm -ti image:version bash -c "cp /source/file /opt/mount/"
Run Code Online (Sandbox Code Playgroud)

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

  • 如果您的图像没有“bash”,您可以使用“sh”代替。 (2认同)

rin*_*ahn 6

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