如何在构建期间将主机卷挂载到 Dockerfile 中的 docker 容器中 [英] How to mount host volumes into docker containers in Dockerfile during build

查看:49
本文介绍了如何在构建期间将主机卷挂载到 Dockerfile 中的 docker 容器中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

原问题:如何在Dockerfile中使用VOLUME指令?

Original question: How to use the VOLUME instruction in Dockerfile?

我要解决的实际问题是——如何在构建期间将主机卷挂载到 Dockerfile 中的 docker 容器中,即在 docker run -v/export:/export 期间具有 功能>docker build.

The actual question I want to solve is -- how to mount host volumes into docker containers in Dockerfile during build, i.e., having the docker run -v /export:/export capability during docker build.

对我来说,这背后的原因是在 Docker 中构建东西时,我不希望那些 (apt-get install) 缓存锁定在单个 Docker 中,而是要共享/重用它们.这是我问这个问题的主要原因.

The reason behind it, for me, is when building things in Docker, I don't want those (apt-get install) caches locked in a single docker, but to share/reuse them. That's the main reason I'm asking about this question.

最新更新:

在 docker v18.09 之前,正确答案应该是以下开头的:

Before docker v18.09, the correct answer should be the one that starts with:

有一种在构建过程中挂载卷的方法,但它不涉及 Dockerfile.

There is a way to mount a volume during a build, but it doesn't involve Dockerfiles.

然而,这是一个陈述不当、组织有序且支持性较差的答案.当我重新安装我的 docker contains 时,我偶然发现了以下文章:

However, that was a poorly stated, organized and supported answer. When I was reinstalling my docker contains, I happened to stumble upon the following article:

Dockerize apt-cacher-ng 服务
https://docs.docker.com/engine/examples/apt-cacher-ng/

这是 docker 对这个/我的问题的解决方案,不是直接而是间接的.这是 docker 建议我们做的正统方式.我承认这比我在这里问的要好.

That's the docker's solution to this/my question, not directly but indirectly. It's the orthodox way docker suggests us to do. And I admit it is better than the one I was trying to ask here.

另一种方式是新接受的答案,例如 v18.09 中的 Buildkit.

Another way is, the newly accepted answer, e.g., the Buildkit in v18.09.

选择适合您的.

是:曾经有一个解决方案——rocker,它不是来自 Docker,但现在该 Rocker 已停产,我将答案恢复为不可能"em> 再次.

Was: There had been a solution -- rocker, which was not from Docker, but now that rocker is discontinued, I revert the answer back to "Not possible" again.

旧更新:所以答案是不可能".我可以接受它作为答案,因为我知道该问题已在 https://github 上进行了广泛讨论.com/docker/docker/issues/3156.我可以理解,对于 docker 开发人员来说,可移植性是一个最重要的问题;但作为一个 docker 用户,我不得不说我对这个缺失的功能感到非常失望.让我引用上述讨论中的一句话来结束我的论点:我想使用 Gentoo 作为基础映像,但绝对不想要 >1GB 的 Portage 树数据在镜像构建后位于任何层中.如果不是因为在安装过程中必须出现在映像中的巨大的 portage 树,您可以拥有一些不错的紧凑型容器."是的,我可以使用 wget 或 curl 来下载我需要的任何东西,但是现在仅仅出于可移植性的考虑迫使我下载 >每次我构建一个 Gentoo 基础镜像时,1GB 的 Portage 树既不高效也不用户友好.此外,软件包存储库将始终位于/usr/portage 下,因此在 Gentoo 下始终可移植.同样,我尊重这个决定,但同时也请允许我表达我的失望.谢谢.

Old Update: So the answer is "Not possible". I can accept it as an answer as I know the issue has been extensively discussed at https://github.com/docker/docker/issues/3156. I can understand that portability is a paramount issue for docker developer; but as a docker user, I have to say I'm very disappointed about this missing feature. Let me close my argument with a quote from aforementioned discussion: "I would like to use Gentoo as a base image but definitely don't want > 1GB of Portage tree data to be in any of the layers once the image has been built. You could have some nice a compact containers if it wasn't for the gigantic portage tree having to appear in the image during the install." Yes, I can use wget or curl to download whatever I need, but the fact that merely a portability consideration is now forcing me to download > 1GB of Portage tree each time I build a Gentoo base image is neither efficient nor user friendly. Further more, the package repository WILL ALWAYS be under /usr/portage, thus ALWAYS PORTABLE under Gentoo. Again, I respect the decision, but please allow me expressing my disappointment as well in the mean time. Thanks.

原始问题详情:

来自

通过卷共享目录
http://docker.readthedocs.org/en/v0.7.3/use/working_with_volumes/

它说数据卷功能自 Docker 远程 API 的第 1 版起就可用".我的 docker 版本是 1.2.0,但我发现上面文章中给出的示例不起作用:

it says that Data volumes feature "have been available since version 1 of the Docker Remote API". My docker is of version 1.2.0, but I found the example given in above article not working:

# BUILD-USING:        docker build -t data .
# RUN-USING:          docker run -name DATA data
FROM          busybox
VOLUME        ["/var/volume1", "/var/volume2"]
CMD           ["/usr/bin/true"]

Dockerfile 中通过 VOLUME 命令将主机安装的卷挂载到 docker 容器的正确方法是什么?

What's the proper way in Dockerfile to mount host-mounted volumes into docker containers, via the VOLUME command?

$ apt-cache policy lxc-docker
lxc-docker:
  Installed: 1.2.0
  Candidate: 1.2.0
  Version table:
 *** 1.2.0 0
        500 https://get.docker.io/ubuntu/ docker/main amd64 Packages
        100 /var/lib/dpkg/status

$ cat Dockerfile 
FROM          debian:sid

VOLUME        ["/export"]
RUN ls -l /export
CMD ls -l /export

$ docker build -t data .
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon 
Step 0 : FROM          debian:sid
 ---> 77e97a48ce6a
Step 1 : VOLUME        ["/export"]
 ---> Using cache
 ---> 59b69b65a074
Step 2 : RUN ls -l /export
 ---> Running in df43c78d74be
total 0
 ---> 9d29a6eb263f
Removing intermediate container df43c78d74be
Step 3 : CMD ls -l /export
 ---> Running in 8e4916d3e390
 ---> d6e7e1c52551
Removing intermediate container 8e4916d3e390
Successfully built d6e7e1c52551

$ docker run data
total 0

$ ls -l /export | wc 
     20     162    1131

$ docker -v
Docker version 1.2.0, build fa7b24f

推荐答案

首先,回答为什么 VOLUME 不起作用?"当您在 Dockerfile 中定义 VOLUME 时,您只能定义目标,而不能定义卷的源.在构建过程中,您只能从中获得一个匿名卷.该匿名卷将在每个 RUN 命令时安装,预先填充映像的内容,然后在 RUN 命令结束时丢弃.仅保存对容器的更改,不保存对卷的更改.

First, to answer "why doesn't VOLUME work?" When you define a VOLUME in the Dockerfile, you can only define the target, not the source of the volume. During the build, you will only get an anonymous volume from this. That anonymous volume will be mounted at every RUN command, prepopulated with the contents of the image, and then discarded at the end of the RUN command. Only changes to the container are saved, not changes to the volume.

自从提出这个问题以来,已经发布了一些可能会有所帮助的功能.首先是多阶段构建,允许您构建磁盘空间效率低的第一阶段,并将所需的输出复制到您发布的最后阶段.第二个功能是 Buildkit,它极大地改变了图像的构建方式,并将新功能添加到构建中.

Since this question has been asked, a few features have been released that may help. First is multistage builds allowing you to build a disk space inefficient first stage, and copy just the needed output to the final stage that you ship. And the second feature is Buildkit which is dramatically changing how images are built and new capabilities are being added to the build.

对于多阶段构建,您将有多个 FROM 行,每一行都开始创建一个单独的图像.默认情况下只标记最后一个图像,但您可以复制前一阶段的文件.标准用途是拥有一个编译器环境来构建二进制或其他应用程序工件,以及一个运行时环境作为复制该工件的第二阶段.你可以:

For a multi-stage build, you would have multiple FROM lines, each one starting the creation of a separate image. Only the last image is tagged by default, but you can copy files from previous stages. The standard use is to have a compiler environment to build a binary or other application artifact, and a runtime environment as the second stage that copies over that artifact. You could have:

FROM debian:sid as builder
COPY export /export
RUN compile command here >/result.bin

FROM debian:sid
COPY --from=builder /result.bin /result.bin
CMD ["/result.bin"]

这将导致构建只包含生成的二进制文件,而不包含完整的/export 目录.

That would result in a build that only contains the resulting binary, and not the full /export directory.

Buildkit 将于 18.09 结束实验.这是对构建过程的完全重新设计,包括更改前端解析器的能力.其中一项解析器更改已经实现了 RUN --mount 选项,该选项允许您为运行命令挂载缓存目录.例如.这是一个挂载一些 debian 目录的目录(重新配置 debian 映像,这可以加快软件包的重新安装速度):

Buildkit is coming out of experimental in 18.09. It's a complete redesign of the build process, including the ability to change the frontend parser. One of those parser changes has has implemented the RUN --mount option which lets you mount a cache directory for your run commands. E.g. here's one that mounts some of the debian directories (with a reconfigure of the debian image, this could speed up reinstalls of packages):

# syntax = docker/dockerfile:experimental
FROM debian:latest
RUN --mount=target=/var/lib/apt/lists,type=cache 
    --mount=target=/var/cache/apt,type=cache 
    apt-get update 
 && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends 
      git

您可以为您拥有的任何应用程序缓存调整缓存目录,例如$HOME/.m2 for maven,或/root/.cache for golang.

You would adjust the cache directory for whatever application cache you have, e.g. $HOME/.m2 for maven, or /root/.cache for golang.

TL;DR:答案在这里:使用 RUN --mount 语法,您还可以从构建上下文绑定装载只读目录.该文件夹必须存在于构建上下文中,并且不会映射回主机或构建客户端:

TL;DR: Answer is here: With that RUN --mount syntax, you can also bind mount read-only directories from the build-context. The folder must exist in the build context, and it is not mapped back to the host or the build client:

# syntax = docker/dockerfile:experimental
FROM debian:latest
RUN --mount=target=/export,type=bind,source=export 
    process export directory here...

请注意,因为目录是从上下文挂载的,所以它也是以只读方式挂载的,您不能将更改推送回主机或客户端.构建时,您需要安装 18.09 或更高版本,并使用 export DOCKER_BUILDKIT=1 启用 buildkit.

Note that because the directory is mounted from the context, it's also mounted read-only, and you cannot push changes back to the host or client. When you build, you'll want an 18.09 or newer install and enable buildkit with export DOCKER_BUILDKIT=1.

如果您收到不支持挂载标志的错误,则表明您没有使用上述变量启用 buildkit,或者您没有使用顶部的语法行启用实验性语法Dockerfile 在任何其他行之前,包括注释.请注意,仅当您的 docker install 内置了 buildkit 支持时,用于切换 buildkit 的变量才会起作用,这需要 Docker 的 18.09 或更高版本,无论是在客户端还是服务器上.

If you get an error that the mount flag isn't supported, that indicates that you either didn't enable buildkit with the above variable, or that you didn't enable the experimental syntax with the syntax line at the top of the Dockerfile before any other lines, including comments. Note that the variable to toggle buildkit will only work if your docker install has buildkit support built in, which requires version 18.09 or newer from Docker, both on the client and server.

这篇关于如何在构建期间将主机卷挂载到 Dockerfile 中的 docker 容器中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆