自 2014 年提出这个问题以来,发生了许多情况,许多事情发生了变化。 我今天再次重温这个话题,我正在第 12 次编辑这个问题以反映最新的变化。这个问题可能看起来很长,但它是按时间倒序排列的,所以最新的变化在顶部,随时停止阅读。
我想解决的问题是——如何在构建过程中将主机卷挂载到 Dockerfile 中的 docker 容器中,即docker run -v /export:/export在docker build.
docker run -v /export:/export
docker build
对我来说,背后的一个原因是在 Docker 中构建东西时,我不希望那些 ( apt-get install) 缓存锁定在单个 Docker 中,而是共享/重用它们。
apt-get install
这就是我问这个问题的主要原因。我今天面临的另一个原因是试图利用来自主机的巨大私人回购,否则我必须git clone使用我的私人 ssh 密钥从 docker 内的私人回购中做,我不知道如何也没有看着呢。
git clone
最新更新:
@BMitch 回答中的 Buildkit
使用该RUN --mount语法,您还可以从构建上下文绑定挂载只读目录…
RUN --mount
它现在已经内置在 docker 中(我认为它是一个第三方工具),只要你的超过 18.09。我的现在是 20.10.7 - https://docs.docker.com/develop/develop- images/build_enhancements/
启用 BuildKit 构建 全新安装 docker 最简单的方法是在调用 docker build 命令时设置 DOCKER_BUILDKIT=1 环境变量,例如: $ DOCKER_BUILDKIT=1 docker build .
启用 BuildKit 构建
全新安装 docker 最简单的方法是在调用 docker build 命令时设置 DOCKER_BUILDKIT=1 环境变量,例如:
$ DOCKER_BUILDKIT=1 docker build .
否则,您将获得:
the --mount option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled
因此,如上所述,这将是我的第二个用例的完美解决方案。
截至 2019 年 5 月 7 日的更新:
在 docker v18.09 之前,正确答案应该是以下开头的那个:
有一种方法可以在构建期间挂载卷,但它不涉及 Dockerfile。
然而,这是一个表述不佳、组织有序且得到支持的答案。当我重新安装我的 docker contains 时,我偶然发现了以下文章:
Dockerize 一个 apt-cacher-ng 服务 https://docs.docker.com/engine/examples/apt-cacher- ng/
这是码头工人对这个/我的问题的解决方案,不是直接而是间接。这是 docker 建议我们做的正统方式。我承认这比我在这里试图问的要好。
另一种方式是 _ 新接受的答案_ ,例如 v18.09 中的 Buildkit。
选择适合您的。
是: 曾经有一个解决方案——rocker,它不是来自 Docker,但是现在这个 rocker 已经停产了,我再次将答案恢复为 “不可能” 。
旧更新: 所以答案是“不可能”。我可以接受它作为答案,因为我知道该问题已在https://github.com/docker/docker/issues/3156进行了广泛讨论。我可以理解,可移植性对于 docker 开发人员来说是一个最重要的问题;但作为 docker 用户,我不得不说我对这个缺失的功能感到非常失望。让我引用上述讨论中的一句话来结束我的论点:“ 我想使用 Gentoo 作为基础镜像,但绝对不希望在构建镜像后的任何层中超过 1GB 的 Portage 树数据。你如果不是在安装过程中必须出现在图像中的巨大的 portage 树,可能会有一些不错的紧凑容器。 ” 是的,我可以使用 wget 或 curl 来下载我需要的任何东西,但事实上,仅仅出于可移植性考虑,现在我每次构建 Gentoo 基础映像时都必须下载 > 1GB 的 Portage 树,这既不高效也不友好。进一步此外,软件包存储库将始终位于 /usr/portage 下,因此在 Gentoo 下始终可移植。再次,我尊重这个决定,但同时请允许我表达我的失望。谢谢。
详细的原始问题 :
从
通过卷共享目录 http://docker.readthedocs.org/en/v0.7.3/use/working_with_volumes/
它说数据卷功能“从 Docker 远程 API 版本 1 开始可用”。我的 docker 版本是 1.2.0,但我发现上面文章中给出的示例不起作用:
# 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 容器中的正确方法是什么?
$ 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 中定义 aVOLUME时,只能定义目标,不能定义卷的源。在构建期间,您只会从中获得一个匿名卷。该匿名卷将在每个RUN命令中安装,预先填充映像的内容,然后在RUN命令结束时丢弃。只保存对容器的更改,而不是对卷的更改。
VOLUME
RUN
自从提出这个问题以来,已经发布了一些可能会有所帮助的功能。首先是多阶段构建,允许您构建磁盘空间低效的第一阶段,并将所需的输出复制到您交付的最后阶段。第二个功能是 Buildkit,它极大地改变了图像的构建方式,并且正在向构建中添加新功能。
对于多阶段构建,您将拥有多FROM行,每行都开始创建单独的图像。默认情况下仅标记最后一个图像,但您可以从以前的阶段复制文件。标准用途是拥有一个编译器环境来构建二进制或其他应用程序工件,以及一个运行时环境作为复制该工件的第二阶段。你可以有:
FROM
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 目录。
Buildkit 将在 18.09 结束实验。这是对构建过程的完全重新设计,包括更改前端解析器的能力。其中一项解析器更改已经实现了RUN --mount允许您为运行命令挂载缓存目录的选项。例如,这是一个挂载一些 debian 目录的目录(通过重新配置 debian 映像,这可以加快软件包的重新安装速度):
# 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 用于 maven,或 /root/.cache 用于 golang。
TL;DR:答案在这里: 使用该RUN --mount语法,您还可以从构建上下文绑定挂载只读目录。该文件夹必须存在于构建上下文中,并且不会映射回主机或构建客户端:
# 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.
export DOCKER_BUILDKIT=1
如果您收到不支持挂载标志的错误,则表明您没有使用上述变量启用 buildkit,或者您之前没有使用 Dockerfile 顶部的语法行启用实验性语法任何其他行,包括注释。请注意,仅当您的 docker install 内置了 buildkit 支持时,切换 buildkit 的变量才有效,这需要 Docker 的 18.09 或更高版本,无论是在客户端还是服务器上。