How to mount host volumes into docker containers in Dockerfile during build
原始问题:如何在dockerfile中使用volume指令?
我要解决的实际问题是--在构建期间如何将主机卷装入dockerfile中的docker容器,即在
对我来说,背后的原因是,在Docker中构建东西时,我不希望那些(
最新更新:
在Docker v18.09之前,正确的答案应该是从以下内容开始的:
There is a way to mount a volume during a build, but it doesn't involve Dockerfiles.
然而,这是一个不恰当的、有组织的和支持的答案。当我重新安装docker contains时,我偶然发现了以下文章:
Dockerize apt缓存服务https://docs.docker.com/engine/examples/apt-cacher-ng/
这是码头工人对这个/我的问题的解决办法,不是直接的,而是间接的。这是道克建议我们做的正统做法。我承认这比我在这里要问的要好。
另一种方法是,新接受的答案,例如v18.09中的buildKit。
选择适合你的。
曾经是:有一个解决方案——rocker,它不是来自docker,但是现在rocker已经停止了,我再次把答案回复到"不可能"。
旧更新:所以答案是"不可能"。我可以接受它作为答案,因为我知道这个问题已经在https://github.com/docker/docker/issues/3156上广泛讨论过。我可以理解,可移植性是Docker开发人员的首要问题;但是作为Docker用户,我不得不说我对这个缺失的特性非常失望。让我引用前面讨论中的一句话来结束我的论点:"我希望使用Gentoo作为基础图像,但绝对不希望在构建图像后,超过1GB的移植树数据出现在任何层中。"如果不是因为安装过程中图像中必须出现巨大的移植树,您可以有一些很好的紧凑的容器。"是的,我可以使用wget或curl下载我需要的任何内容,但事实上,现在仅仅考虑移植性就迫使我在每次构建Gentoo基础图像时下载超过1GB的移植树,这就不在效率高,不易使用。此外,包存储库将始终位于/usr/portage下,因此在gentoo下始终是可移植的。我再次尊重这个决定,但请允许我同时表达我的失望。谢谢。
原始问题详情:
从
通过卷共享目录http://docker.readthedocs.org/en/v0.7.3/use/workingu与卷/
它说数据卷功能"从Docker远程API的版本1开始就可用"。我的Docker是1.2.0版,但我发现上面文章中给出的示例不起作用:
1 2 3 4 5 | # 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容器的正确方法是什么?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | $ 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 |
不可能使用
无法在生成期间装载主机卷。没有特权构建和装载主机也会严重降低可移植性。您可能想尝试使用wget或curl下载构建所需的任何内容并将其放置到位。
更新:有人只是不把不当作答案,我非常喜欢它,尤其是这个特别的问题。
好消息,现在有办法了--
解决方案是rocker:https://github.com/grammarly/rocker
John Yani说,"在我看来,它解决了dockerfile的所有弱点,使其适合开发。"
摇杆https://github.com/grammarly/rocker网站
By introducing new commands, Rocker aims to solve the following use cases, which are painful with plain Docker:
Mount reusable volumes on build stage, so dependency management tools may use cache between builds. Share ssh keys with build (for pulling private repos, etc.), while not leaving them in the resulting image. Build and run application in different images, be able to easily pass an artifact from one image to another, ideally have this logic in a single Dockerfile. Tag/Push images right from Dockerfiles. Pass variables from shell build command so they can be substituted to a Dockerfile. And more. These are the most critical issues that were blocking our adoption of Docker at Grammarly.
更新:根据Github上的官方项目报告,Rocker已经停产。
As of early 2018, the container ecosystem is much more mature than it was three years ago when this project was initiated. Now, some of the critical and outstanding features of rocker can be easily covered by docker build or other well-supported tools, though some features do remain unique to rocker. See https://github.com/grammarly/rocker/issues/199 for more details.
首先,回答"为什么
由于这个问题已经被提出,一些功能已经发布,可能会有所帮助。首先是多阶段构建,它允许您在第一阶段构建效率低下的磁盘空间,并将所需的输出复制到所发送的最后一个阶段。第二个特性是buildKit,它显著地改变了图像的构建方式,并在构建中添加了新的功能。
对于多阶段构建,您将拥有多个
1 2 3 4 5 6 7 | 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"] |
这将导致生成只包含结果二进制文件,而不包含完整/导出目录。
buildKit将于2009年18月退出实验。这是对构建过程的完全重新设计,包括更改前端解析器的能力。其中一个解析器更改已经实现了
1 2 3 4 5 6 7 | # 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 |
您可以根据您拥有的任何应用程序缓存来调整缓存目录,例如对于maven为$home/.m2,对于golang为/root/.cache。
tl;dr:答案在这里:使用
1 2 3 4 | # syntax = docker/dockerfile:experimental FROM debian:latest RUN --mount=target=/export,type=bind,source=export \ process export directory here... |
请注意,由于目录是从上下文装载的,所以它也是以只读方式装载的,您不能将更改推回到主机或客户机上。当您构建时,您将需要一个18.09或更高版本的安装并启用带有
有一种方法可以在构建期间装载卷,但它不涉及dockerfiles。
该技术将从您想要使用的任何基础创建一个容器(使用
这样不仅可以省去您不想要的多余文件(这对安全文件也很好,比如ssh文件),还可以创建单个映像。它有缺点:commit命令不支持所有dockerfile指令,而且如果您需要编辑构建脚本,它也不允许您在停止时拾取。
运行容器时,会在主机上创建一个目录并将其装入容器中。你可以找到这个目录
1 2 | $ docker inspect --format"{{ .Volumes }}" <ID> map[/export:/var/lib/docker/vfs/dir/<VOLUME ID...>] |
如果要从主机在容器中装入目录,则必须使用
1 | docker run -v /export:/export data |
所以您将使用容器中的hosts文件夹。
我认为您可以通过一个docker命令来运行构建,该命令本身在docker容器中运行。见docker现在可以在docker docker博客中运行。使用了这样一种技术,但实际上是通过容器访问外部Docker,例如,在探索如何创建最小的Docker容器Xebia博客时。
另一篇相关文章是优化docker images centurylink labs,它解释了如果在构建过程中下载内容,可以通过一个运行步骤下载、构建和删除下载来避免在最终图像中浪费空间。
很难看,但我的外表是这样的:
Dockerfile:
1 2 3 | FROM foo COPY ./m2/ /root/.m2 RUN stuff |
图像:
1 2 3 4 5 | docker build . -t barImage container="$(docker run -d barImage)" rm -rf ./m2 docker cp"$container:/root/.m2" ./m2 docker rm -f"$container" |
我有一个Java构建,将宇宙下载到/root / m2,并且每次都这样做。生成后,
这类似于一个卷的工作方式(即在构建之间保持)。