Moby: 仅构建时间 -v 选项

创建于 2015-06-21  ·  258评论  ·  资料来源: moby/moby

正如@cpuguy83https://github.com/docker/docker/issues/3156中所建议的那样
这是构建时灵活的 -v 选项的用例。

构建 Docker 映像时,我需要安装数据库和应用程序。 它全部包含在两个 tarball 中:1 个用于 DB,1 个用于需要安装在其中的应用程序(模式、对象、静态数据、凭据等)。 然后,整个解决方案通过一个 shell 脚本运行,该脚本处理多个 shell 变量并相应地调整操作系统凭据和其他内容。
当我分解上面的压缩包(或使用 Dockerfile ADD 指令)时,整个事情膨胀到大约 1.5GB(!)。 不理想,你可以想象。

我希望这个 '-v /distrib/ready2installApp:/distrib' 指令仍然可行(就像今天在 Dockerfile 中一样)

我想将声明性构建过程(基础设施即代码)与容器运行时可部署工件分离。 我不想处理我不需要的 1.5GB 的自重。

我们可以在 Dockerfile 的末尾运行一个 --unmount-volume 选项吗?
要么
鉴于卷现在在 Dockerfile 中的工作方式,也许我们需要一个新的 Dockerfile 指令来用于人们在安装时使用的临时卷? 我认为@fatherlinux提供的 Puppet 示例处于类似的行...
要么
各位能想到什么。
目标是避免必须携带所有对已部署的应用程序或服务无用的重量。 但是,@install-time 需要自重。 不是每个人都有来自官方存储库的简单“yum install”。 :)

非常感谢您

arebuilder kinfeature

最有用的评论

对于这个特性,我有一个稍微不同的用例——缓存由ASP.Net 5 包管理器下载/更新的包。 包管理器管理自己的缓存文件夹,所以最终我只需要一个可以在构建之间重复使用的文件夹。

IE:

docker build -v /home/dokku/cache/dnx/packages:/opt/dnx/packages -t "dokku/aspnettest" .

所有258条评论

我正在寻找类似的解决方案。

问题

最近我工作的企业启用了带有 SSL 检查的 Zscaler 代理,这意味着在构建期间安装了证书并设置了一些环境变量。

一个临时的解决方案是创建一个带有证书和环境变量集的新 Dockerfile。 但从长远来看,这似乎并不合理。

所以,我的第一个想法是使用 HTTP 和 HTTPS 设置一个透明代理,但我需要在构建期间再次传递证书。

理想的场景是使用相同的 Dockerfile,我将能够在我的笔记本电脑、家庭和企业中构建我的镜像。

可能的解决方案

# Enterprise
$ docker build -v /etc/ssl:/etc/ssl -t myimage .

# Home
$ docker build -t myimage .

对于这个特性,我有一个稍微不同的用例——缓存由ASP.Net 5 包管理器下载/更新的包。 包管理器管理自己的缓存文件夹,所以最终我只需要一个可以在构建之间重复使用的文件夹。

IE:

docker build -v /home/dokku/cache/dnx/packages:/opt/dnx/packages -t "dokku/aspnettest" .

@yngndrw您的建议对我来说也可以,即,我们需要在构建时安装额外的资源,这些资源在运行时不需要,因为它们已安装在容器中。

FWIW 我在这些页面的某个地方看到有人说(我希望我的解释是正确的)“在类似的主机上解决你的编译问题,然后在容器中安装可部署的工件或 exe”。
恐怕不是那么简单的家伙。 有时,我需要安装在 /usr/bin 中,但我还需要编辑一些配置文件。 我检查我正在运行的操作系统、我需要调整的内核参数、我需要根据变量或清单构建文件创建的文件。 有许多依赖项对编译产品的简单副本不满意。

我重申我在打开问题时所说的话:清单声明文件及其进程和工件的运行时之间存在差异。
如果我们真的相信基础设施即代码以及不可变的基础设施,那么 Docker 本身正在进一步推广并且我喜欢它,那么这需要认真考虑 IMO(请参阅本文第 1 篇中的膨胀)

再次感谢你

另一个真正有趣的用例是升级软件。 有时,就像使用 FreeIPA 一样,您应该使用生产数据的副本进行真正的测试,以确保所有不同的组件都可以干净地升级。 您仍然想在“构建”环境中进行升级。 您希望数据的生产副本存在于其他地方,这样当您将容器的新升级版本移动到生产环境时,它们可以堆积您进行升级的确切数据。

另一个例子是 Satellite/Spacewalk,它经常更改架构,甚至在 5.6 (IIRC) 版本中将数据库从 Oracle 更改为 Postgresql。

当我在容器化构建中进行软件升级时临时需要访问数据时,有很多很多情况,尤其是分布式/微服务......

本质上,我现在被迫通过运行带有 -v 绑定挂载的常规容器进行手动升级,然后执行“docker commit”。 我不明白为什么自动 Dockerfile 构建不能提供相同的功能?

支持@yngndrw指出缓存:完全相同的推理适用于许多流行的项目,例如 Maven、npm、apt、rpm —— 允许共享缓存可以显着加快构建速度,但不能使其进入最终映像。

我同意@stevenschlansker。 它可以是附加缓存卷的许多要求,或者某种几千兆字节的数据,它们必须在最终图像上呈现(以解析状态),但不能作为原始数据。

我也一直被对扩展docker build以支持docker run可以使用的卷的持续阻力所困扰。 我还没有发现“独立于主机的构建”的口头禅很有说服力,因为当您每次重建时都需要重新下载整个包存储库时,它似乎只会使开发和迭代 Docker 映像变得更加困难和耗时一个图像。

我最初的用例是希望缓存 OS 包存储库以加快开发迭代。 我已经成功使用的一种解决方法类似于@fatherlinux建议的方法,即完全放弃与docker buildDockerfile的搏斗,并使用docker run从头开始docker commit

作为一个实验,我使用一些 POSIX shell 脚本将我的技术扩展到docker build的成熟替代品: dockerize

如果有人想测试这个脚本或一般方法,请让我知道它是否有趣或有帮助(或者它是否对你有用)。 要使用,请将脚本放在 PATH 中的某个位置,并将其添加为构建脚本的 shebang( #!东西),然后在标记 Docker 安装脚本开始的第二个 shebang 行之前设置相关的环境变量。

FROMRUNDIRVOLUME变量将自动作为参数传递给docker run
TAGEXPOSEWORKDIR变量将自动作为参数传递给docker commit

所有其他变量将在 shell 中评估并作为环境参数传递给docker run ,使它们在您的构建脚本中可用。

例如,此脚本将在构建之间缓存和重用 Alpine Linux 包(VOLUME 将主目录挂载到 CACHE,然后将其用作安装脚本中操作系统包存储库缓存的符号链接):

#!/usr/bin/env dockerize
FROM=alpine
TAG=${TAG:-wjordan/my-image}
WORKDIR=/var/cache/dockerize
CACHE=/var/cache/docker
EXPOSE=3001
VOLUME="${HOME}/.docker-cache:${CACHE} ${PWD}:${WORKDIR}:ro /tmp"
#!/bin/sh
ln -s ${CACHE}/apk /var/cache/apk
ln -s ${CACHE}/apk /etc/apk/cache
set -e
apk --update add gcc g++ make libc-dev python
[...etc etc build...]

因此,在上周在 MesoCon 与来自 Docker 的法国特遣队 :) 会面之后(大家很高兴),我意识到他们在内部也遇到了同样的问题,他们开发了一个 hack,可以将他们需要的东西复制到一个新的苗条图像中.
我想说的是,黑客在企业界是受欢迎的;)并且这个请求应该得到妥善处理。
谢谢大家听...

我也赞成添加构建时-v标志,以通过在它们之间共享缓存目录来加速构建。

@yngndrw我不明白你为什么要关闭两个相关的问题。 我阅读了您的 #59 问题,但我不明白这与此有何关系。 在某些情况下,当运行时不需要容器时,它会变得非常臃肿。 请阅读第 1 篇文章。
我希望我不会在这里错过任何东西......因为这是漫长的一天:-o

@zrml问题https://github.com/aspnet/aspnet-docker/issues/59与 docker 在构建所有 docker 文件期间提供的内置每层缓存有关,但当前的问题与我们正在谈论使用主机卷来提供特定于 dockerfile 的缓存,这取决于 dockerfile 对卷的特殊使用。 我关闭了问题https://github.com/aspnet/aspnet-docker/issues/59 ,因为它与 aspnet-docker 项目/存储库没有具体关系。

我认为您所指的另一个问题是问题https://github.com/progrium/dokku/issues/1231 ,这是关于 Dokku 进程明确禁用内置 docker 层缓存的问题。 Michael 对 Dokku 进行了更改以允许此行为可配置,这解决了有关 Dokku 项目/存储库的问题,因此该问题也已关闭。

可能仍然存在与 Docker 相关的未解决问题(即为什么 Docker 没有像我在问题 https://github.com/aspnet/aspnet-docker/issues/59 中预期的那样处理内置层缓存),但是我还没有机会弄清楚为什么会这样并确认它是否仍在发生。 如果它仍然是一个问题,那么应该为此项目/存储库提出一个新问题,因为它与当前问题不同。

@yngndrw完全正确,所以我们同意这是不同的并且众所周知的@docker.com 所以如果你不介意我会重新打开它......好吧我不能。 请问你介意吗?
至少在我们关闭它之前,我希望看到我们在 SF 的同事的一些评论

顺便说一句, @cpuguy83要求我打开一个用户案例并解释一切,来自日志 #3156

@zrml我不确定我是否关注-您想重新打开https://github.com/aspnet/aspnet-docker/issues/59吗? 这不是 /aspnet/aspnet-docker 问题,所以我认为重新打开该问题是不对的。 它确实应该是 /docker/docker 上的一个新问题,但需要进行验证,并且需要首先生成可重现的步骤。

不,不.. 你昨天关闭的这个#14080。

这个问题还开吗?

@yngndrw我相信我误读了红色的“关闭”图标。 道歉。

衷心同意 build time -v 将是一个巨大的帮助。

构建缓存是一种用例。

另一个用例是在构建时使用 ssh 密钥从私有存储库构建而不将它们存储在层中,从而消除了对黑客(尽管设计良好)的需要,例如: https ://github.com/dockito/vault

我在这里发表评论是因为这是企业界的地狱。
我们有一个 SSL 拦截代理,虽然我可以通过它引导流量,但大量项目认为它们具有良好的 SSL 连接,所以它们死得很惨。

即使我的机器(以及 docker builder)信任代理,docker 图像也不信任。
最糟糕的最佳实践是现在在容器内使用 curl,这很痛苦,我必须修改 Dockerfile 以使它们均匀构建。 我可以使用 -v 选项安装证书,并且很高兴。

说到这里。 与其说是 docker 的错,不如说是包管理器在使用类似于 apt-get 工作方式的系统时使用 https 的错误。 因为这仍然是安全且可验证的,并且还可以通过 http 代理缓存。

@btrepp感谢您提供另一个很好的用例。

我可以想到另一种情况。

我想用我的 dockerfiles 做的一件事是不将构建工具与“已编译”的 docker 文件一起发布。 没有理由 C 应用程序需要 gcc,也没有 ruby​​ 应用程序需要映像中的捆绑程序,但目前使用 docker build 同时拥有它。

我的一个想法是指定一个 dockerfile,在其中构建时运行多个 docker 命令。 下面的伪 dockerfiles。

构建其他人的 Docker 文件

FROM dockerbuilder
RUN docker build -t docker/builder myapp/builder/Dockerfile
RUN docker run -v /app:/app builder
RUN docker build -t btrepp/myapplication myapp/Dockerfile

btrepp/myapplication dockerfile

FROM debian:jessie+sayrubyruntime
ADD . /app //(this is code thats been build using the builder dockerfile
ENTRYPOINT ["rails s"]

在这里,我们有一个临时容器,它执行所有捆绑安装/包管理和任何构建脚本,但它会生成运行时容器所需的文件。

然后运行时容器只添加这个结果,这意味着它不需要安装 ruby​​ 。 在 GCC 甚至更好的静态链接 go 的情况下,我们可能不需要除核心 OS 文件之外的任何东西来运行。

这将使 docker 图像保持超轻。

这里的问题是临时构建器容器最终会消失,这意味着如果没有加载各种缓存的能力,它将非常昂贵,我们将抓住debian:jessie一大堆时间。

我见过人们使用这样的某些技术,但是使用外部 http 服务器来添加构建文件。 我宁愿让这一切都由 docker 构建。 尽管可能有一种方法可以使用 docker 映像来正确执行此操作。 使用 run 并因此能够安装卷。

这是另一个例子。 假设我想为 systemtap 构建一个容器,其中包含内核的所有调试符号(它们是 Yuuuuge)。 我必须挂载底层的 /lib/modules 以便 yum 命令知道要安装哪些 RPM。

此外,也许我宁愿将它们放在 1.5GB 图像以外的地方(来自调试符号)

我去写了一个 Dockerfile,然后意识到这是不可能的:-(

docker run --privileged -v /lib/modules:/lib/modules --tty=true --interactive=true rhel7/rhel-tools /bin/bash
yum --enablerepo=rhel-7-server-debug-rpms install kernel-debuginfo-$(uname -r) kernel-devel-$(uname -r)
docker ps -a
CONTAINER ID        IMAGE                     COMMAND             CREATED             STATUS                        PORTS               NAMES
52dac30dc495        rhel7/rhel-tools:latest   "/bin/bash"         34 minutes ago      Exited (0) 15 minutes ago                         dreamy_thompson
docker commit dreamy_thompson stap:latest

https://access.redhat.com/solutions/1420883

我想从 #3949 在这里重复我的用例,因为该错误已因其他原因关闭。

我真的很想在 docker 中对专有软件进行沙箱处理。 我将它托管在任何地方都是违法的,而且下载过程实际上(或合法地)无法实现自动化。 安装程序总共达到 22GB(每个版本都在变大)。 我认为期望在构建时将其复制到 docker 映像中是愚蠢的。

这个需要的功能有什么消息吗?
谢谢

_用户投票_

_在此讨论中有更改时获得通知的最佳方法是单击右上角的订阅按钮。_

下面列出的人对您的有意义的讨论表示赞赏,并随机 +1:

@vad

+1 此功能!

另一个用例是在构建时使用 ssh 密钥从私有存储库构建而不将它们存储在层中,从而消除了对黑客(尽管设计良好)的需要,例如: https ://github.com/dockito/vault

这也是我们的用例(在这种情况下,使用主机上的 tmpfs 呈现 ssh 密钥)。

另一个用例是用于 CI 服务器上node_modules目录的本地缓存,以减少构建时间。
npm install非常慢,即使在当前的“最佳”情况下package.jsonADD编辑到图像, npm install运行,然后才运行添加的实际项目源代码并建立在对package.json的更改的基础上,所有依赖项都必须再次重新下载。

有关 Node/npm 方面的问题,请参阅 npm/npm#8836。

相关的 aspnet-docker 问题涉及缓慢的包恢复和缓存层中当前包的结果图像大小。 使用已安装的卷来缓存包会更好。
https://github.com/aspnet/aspnet-docker/issues/123

这不是特定于语言的问题,鉴于包管理器现在是一个公认的标准,它将影响许多人。

OP 已经解决了这个问题,因为“docker build -v”将极大地帮助将构建过程与运行时环境分离。

我已经看到了几个现在构建“Mulberry harbours”的项目,这些项目然后用于构建实际的 docker,然后推送/分发。 从管理和计算资源的角度来看,这过于复杂,这反过来又会导致 CI​​ 和单元测试速度变慢,并且总体上会降低开发工作流的生产力。

我一直在考虑这个,我能想到的另一个选择是将图层标记为“src”图层的能力。

这些层的某些东西只能在 docker 构建期间访问,但不能拉入生成的图像文件。

这样 docker 可以缓存早期的层/图像,临时构建工件,但这些不是利用最终图像所必需的。

例如。

FROM ubuntu
RUN apt-get install gcc
ADDPRIVATE . /tmp/src <--these can be cached by docker locally
RUNPRIVATE make     <-- basically these layers become scoped to the current build process/dockerfile
RUN make install <--result of this layer is required.

当然,这意味着您需要知道自己做得更好,因为您很可能会忽略关键文件。

@yngndrw
对于像 netcore 这样的情况,一个更好的解决方案是让他们不使用 HTTPS 进行包管理,然后设置 iptables+squid 为 docker 构建提供透明的缓存代理就很简单了。我个人认为这些包管理器应该提升他们的游戏,由于 ssl resigning,它们在企业环境中使用起来很糟糕,而诸如 apt-get 之类的东西工作得非常好,并且已经可以使用 iptables+squid for docker 进行缓存。

我还可以看到使用构建时间量的不利之处,dockerfile 将无法重现,并且需要在 docker build -t btrepp/myapp 之外进行额外设置。这也将使 dockerhub 上的自动构建变得困难。

@btrepp :我喜欢你的建议。 我什至可以使用 Docker 告诉我们的硬编码(我知道这通常是一件坏事)TMP 目录来为我的用例而活,这样他们就可以知道何时从他们可以忘记/遗漏的所有层构建最终工件安装在 /this_is_the_tmp_explosion_folder_that_will_be_removed_from_your_final_container_image
很容易......

@btrepp我非常喜欢你的源层想法。

然而,关于不使用 SSL 的包管理器,我不得不不同意。

如果您想缓存这样的包,那么您可能应该使用(本地)私有包源,而不是镜像官方源。 恢复到 HTTP 对我来说似乎是个坏主意,特别是考虑到很多包管理器似乎没有签署他们的包,因此依赖于 HTTPS。

有一个工具语法/摇杆可以在此问题尚未修复时使用。

@yngndrw

我的观点是本地代理等是一个早已解决的问题。 包管理器只需要验证,他们不需要隐私。 使用 https 是一种提供验证的懒惰方式,但它带有隐私附件。

当通过 http(s) 下拉时,“super_awesome_ruby_lib”需要私有的原因为零。 更好的方法是让红宝石有一个钥匙圈。 甚至是一个已知的公钥,并为其签名包。 这或多或少是 apt-get 的工作原理,并允许标准的 http 代理缓存内容。

关于本地私有包提要,docker 本身甚至不能很好地支持这一点。 禁用标准提要的方法为零,如果 https 证书不在证书存储中,它_rightly_会丢失它。 我很确定 docker 在拉取图像时也总是希望至少检查主提要。 Afaik 火箭/rkt 实现将使用签名+http 来获取容器图像。

如果构建时间量的主要动机只是缓存包,那么我认为应该对包管理器施加压力,以更好地支持缓存,而不是损害目前 docker 的一些自动化/纯粹性。

需要明确的是,我不提倡包管理器切换到只使用 http 并删除 https。 他们确实需要验证包以防止中间人攻击。 他们不需要的是使用 https 作为“安全捕获所有大锤”提供的隐私方面。

这是一个非常狭隘的观点。 你要求整个包管理器改变他们的行为方式,以适应 Docker 对他们认为应用程序将如何构建的规定。

还有很多其他例子说明为什么在这个线程中这是必要的。 说“你应该改变所有用于构建应用程序的工具的工作方式”并不能解决问题,它只会把用户赶走。

(我也强烈不同意 Docker 对公共注册表的附加——我更愿意禁止访问公共注册表,并且只允许使用我们内部的注册表。但这完全是一个不同的主题。)

对我来说,我还需要docker build -v

在我们的例子中,我们想要构建一个包含相关产品的预配置安装的映像,并且安装程序超过2GB 。 无法挂载主机卷,即使我们已经在主机操作系统中下载,我们也无法使用安装程序构建映像,为此我们可以使用各种工具/协议,例如使用 https cert/auth 的代理,或者甚至有点洪流。

作为一种解决方法,我们必须在docker build期间使用 wget 重新下载安装程序,这是一个非常受限制的环境,不太方便,更耗时且容易出错。

此外,由于产品安装/配置选项的灵活性,我们将预装产品的图像发送出去更有意义,而不是仅仅通过安装程序发送图像。

@thaJeztah这有可能发生吗?

Fwiw 这是我不(或真的,不能)使用 docker 的唯一原因

我们在包含 -v 选项的 Red Hat 版本的 docker 中提供了一个补丁。 但真正的解决方案是构建新的和不同的方法来构建 OCI 容器映像,而不是 docker build。

@rhatdan RHEL 还是 Fedora?

我们还在resin.io 的内部版本的docker 中实现了docker build 的-v 选项。 你可以在这里找到差异https://github.com/resin-io/docker/commit/9d155107b06c7f96a8951cbbc18287eeab8f60cc

@rhatdan @petrosagg你可以为此创建一个 PR 吗?

@jeremyherbert补丁位于所有最新版本的 RHEL、CentOS 和 Fedora 中的 docker 守护进程中......

@graingert我们过去曾提交过,但已被拒绝。

@rhatdan你有链接吗?

@runco​​m你有链接吗?

@thaJeztah这是你们会拒绝的吗?

以下是已关闭或未回复的现有问题的列表:
https://github.com/docker/docker/issues/3949
https://github.com/docker/docker/issues/3156
https://github.com/docker/docker/issues/14251
https://github.com/docker/docker/issues/18603

有关 RHEL/CentOS/Fedora 中使用的 Project Atomic 补丁的信息可以在以下位置找到:
http://www.projectatomic.io/blog/2016/08/docker-patches/

@daveisfera看起来他们只添加 R 卷而不是 RW 卷,所以它不适用于@yngndrw和我的用例。

@graingert为什么需要 RW 卷? 我确实将只读理解为某些情况下的解决方法。

测试模式迁移将是一个很好的理由......

2016 年 11 月 1 日上午 10:36,Brian Goff 写道:

@graingert https://github.com/graingert为什么需要 RW 卷?
我确实将只读理解为某些情况下的解决方法。


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看
https://github.com/docker/docker/issues/14080#issuecomment -257582035,
或使线程静音
https://github.com/notifications/unsubscribe-auth/AAHLZdp0D6fAtuNglajPBIwnpWGq3slOks5q5050gaJpZM4FIdOc。

斯科特·麦卡蒂

斯科特。 [email protected]

http://crunchtools.com

@fatherlinux

@cpuguy83 RW 的另一个用例是ccache

@fatherlinux我不确定我是否遵循。 为什么你需要一个卷呢? 另外为什么必须在构建阶段完成?

对于这个功能,我有一个稍微不同的用例——缓存由 ASP.Net 5 包管理器下载/更新的包。 包管理器管理自己的缓存文件夹,所以最终我只需要一个可以在构建之间重复使用的文件夹。

我会绑定 mount 例如:

docker build -v /home/jenkins/pythonapp/cache/pip:/root/.cache/pip  -t pythonapp .
docker build -v /home/jenkins/scalaapp/cache/ivy2:/root/.ivy2  -t scalaapp .

因为有很多时候模式迁移必须在什么时候完成
软件已安装。 如果你运行只读容器,你应该
永远不要安装软件,除非你在
构建阶段......

2016 年 11 月 1 日上午 10:42,Brian Goff 写道:

@fatherlinux https://github.com/fatherlinux我不确定我是否遵循。
为什么你需要一个卷呢? 还有为什么必须在
构建阶段?


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看
https://github.com/docker/docker/issues/14080#issuecomment -257583693,
或使线程静音
https://github.com/notifications/unsubscribe-auth/AAHLZfhBG8RUWtqPD-6RaLC7uoCNc-3nks5q50_TgaJpZM4FIdOc。

斯科特·麦卡蒂

斯科特。 [email protected]

http://crunchtools.com

@fatherlinux

我知道这个目录的内容不会导致构建依赖于主机(缺少这些挂载将导致构建无论如何都可以工作,只是更慢)

NFS 像 30 年前一样解决了这个问题......

2016 年 11 月 1 日上午 10:45,Thomas Grainger 写道:

我知道这个目录的内容不会停止构建
幂等或依赖主机(缺少这些挂载将导致
无论如何构建工作)


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看
https://github.com/docker/docker/issues/14080#issuecomment -257584576,
或使线程静音
https://github.com/notifications/unsubscribe-auth/AAHLZS75Vq0BSEvUjI2oXORsS0el2mwOks5q51CQgaJpZM4FIdOc。

斯科特·麦卡蒂

斯科特。 [email protected]

http://crunchtools.com

@fatherlinux

NFS 像 30 年前一样解决了这个问题......

没有帮助的评论

@graingert抱歉,这严重错误。 我试图反应太快并且没有提供足够的背景信息。 严肃地说,我们正在将 NFS 与 CRIO 结合使用,以解决其中一些类型的问题。

镜像注册表和 bulds 有很多共同点。 你所说的基本上是一个缓存问题。 NFS,特别是内置的缓存可以使构建主机独立并为您处理所有缓存。

因此,即使使用 -v 构建时间选项,构建也不必仅锁定到一个主机。 它可能不是独立于 Internet 规模的,但对于许多将构建环境控制到单个站点或位置的人来说已经足够了。

@fatherlinux我会使用 gitlab 或 travis 缓存来获取缓存目录并上传/下载到 S3

@graingert是的,但这仅适用于某些类型的数据/应用程序,也仅适用于存储桶级别,不适用于 posix 元数据和块级别。 对于某些类型的前端和中间件应用程序,没问题。 对于数据库模式迁移,您需要提前测试并在本地缓存以提高速度,并且通常需要是 posix。

想象一下,我有一个带有 1TB 数据的 MySQL Galera 集群,我想做一个升级,它们都在容器中。 Containerized/Orchestrated 多节点,分片 Galera 真的很方便。 我不想在每次升级期间都手动测试架构迁移。

我想对数据卷(Kube 世界中的 pv)进行快照,将其公开给构建服务器,然后测试升级和模式迁移。 如果一切正常并且测试通过,那么我们构建生产容器并让模式迁移在生产中发生......

@graingert对不起,忘记添加,然后丢弃在测试运行中使用的快照......我不想单独编排构建和测试事件,尽管这是可能的......

@fatherlinux我认为这是一个正交用例......

@graingert不是有用的评论。 与什么正交? 与构建期间对 -v 的请求正交,这就是我理解的这次对话的内容?

我看到这个标志有几种不同的用途。

  • 缓存,在 docker build 服务器之间共享
  • 一个类似于 ADD 的关键字,仅在单个 Dockerfile 的“构建期间”应用。 例如添加一个大文件,然后将其从图像中排除。
  • 忽略所有输出的类似 ADD+RUN 的关键字。 例如,添加一个巨大的文件,然后运行一个步骤并忽略对图像的任何更改 - 在一个步骤中添加 + 运行,然后跳过一层。

后两个用例可以用两个新关键字更干净地解决。

BUILDCONSTFILE <path>

在每次运行之前运行COPY <path> ,然后从图像中删除<path>

TEST <cmd> WITH <paths>

它将复制路径,运行命令,然后以 0 退出状态继续从父映像构建,否则将停止构建

我个人认为 TEST ... WITH 最好在另一个 CI 步骤中处理,该步骤测试你的容器作为一个整体

让我以此作为序言:我_认为_我可以添加--mount来构建(“-v”可能不是那么多)。 不能 100% 确定实施、如何处理(或不处理)缓存等。

对于 docker 项目,我们所做的是构建一个构建器映像。
它基本上有我们需要的一切,复制代码,但实际上并没有构建 docker。
我们有一个Makefile来协调这个。 所以make build构建图像, make binary构建二进制文件, build作为依赖,等等。

制作二进制文件运行构建映像并进行构建,这样我们就可以挂载我们需要的内容,包括用于增量构建的包缓存。
其中大部分都非常简单明了,而且很容易编排。
所以今天肯定有处理这种情况的方法,只是 docker 不能 100% 处理它(这不一定是坏事),你必须让你的 CI 系统工作。

@cpuguy83我认为这将解决我的大部分用例。 我明白了,你的意思是 --mount 表示只读吗? 和 -v 被读/写?

@cpuguy83我们还主要构建“构建器”图像,恕我直言,这正成为一种越来越普遍的模式......

@fatherlinux群服务,现在(对于 1.13) docker run支持--mount更加精确和灵活: https ://docs.docker.com/engine/reference/commandline/service_create/#

看起来文档缺少第三种类型的挂载tmpfs

啊,太好了,谢谢。。。

2016 年 11 月 1 日下午 2:20,Brian Goff 写道:

@fatherlinux https://github.com/fatherlinux群服务和现在
(对于 1.13)|码头运行| 支持 |--mount| 哪个更精确
灵活:
https://docs.docker.com/engine/reference/commandline/service_create/#/add -bind-mounts-or-volumes

看起来文档缺少第三种类型的挂载,|tmpfs|。


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看
https://github.com/docker/docker/issues/14080#issuecomment -257648598,
或使线程静音
https://github.com/notifications/unsubscribe-auth/AAHLZXv_VBfVi4WUAjVijE-SKR0ErRC4ks5q54L2gaJpZM4FIdOc。

斯科特·麦卡蒂

斯科特。 [email protected]

http://crunchtools.com

@fatherlinux

@cpuguy83我们也经常使用构建器模式,我们需要缓存不保留在图像中并且在层失效后仍然存在。

我们构建 Yocto 映像,并在 NFS 存储上共享 sstate 缓存。 另一个用例是 npm 缓存,因此您可以使整个RUN npm install层无效,但由于缓存包而更快地重新计算它。

作为基于@graingert的帖子的一种可能的妥协,是否可以在 dockerfile 中没有您的大文件的可选哈希,然后 docker 在运行构建时检查这个? 那时确定性构建不会有任何问题,并且对于构建人员来说,他们没有所需的依赖项是显而易见的,而不是在某个时候它只是以一个奇怪的错误爆炸。 ssh 密钥等也是如此,无论如何都需要与 dockerfile 一起分发。

我还认为任何需要复制大文件的想法都不理想。 我有兴趣使用的文件大小大约为 10-40GB,即使使用好的 ssd 至少需要一两分钟的复制时间。 这是我对 docker 中的 ADD 指令的问题; 我不想每次构建图像​​时都为我的图像添加 30GB,并且必须处理所有这些额外的可用空间,以及需要压缩图像。

这不适用于我们使用它的目的。 我们有一个卷,其中包含来自 yocto 构建系统的 sstate 缓存,它在构建中绑定挂载 RW,因为任何缓存未命中都将在构建期间计算并保存在 sstate 中以供将来使用。 我们的目录也大约为 30GB,因此即使计算哈希也需要一段时间。

我从不理解确定性构建概念。 即使使用今天的语义,也有一些方法可以让你自己开枪。 例如,您可以从内部 IP curl的东西。 突然间,这个 Dockerfile 并不适用于任何地方,而且它依赖于主机。 但是有一些合理的案例可以说明您为什么要这样做。 例如本地 HTTP 缓存。

因此,既然构建无论如何都不是确定性的,并且由于今天可以通过网络模拟绑定安装的卷,那么为什么不提供一种本地方式来执行此操作并在需要时提供适当的警告呢?

@petrosagg @zrml @thaJeztah我们所知道的是:

  • 如果我们通过 #7115 #3156 进行鞭打,我们可以找到一长串多年前讨论同样问题的问题
  • 大多数都因可复制性原因而关闭(或旧的Dockerfile syntax is frozen注释,然后在添加HEALTHCHECK指令后,冻结被删除但问题仍然关闭)
  • 多年来,这个问题已经阻止了许多团队在日常开发中拥有良好的容器可用性/生产力。 正如@btrepp所说,这是地狱
  • Docker 的人都知道这个问题,但这会带来一个类哦,我的 docker build 坏了! 由于共享缓存不好的问题
  • 但是从磁盘缓存转移到网络缓存似乎并没有以任何方式提高构建的可靠性,就像一个美化的 http 缓存,并且已经发现它使事情变得更糟(为每个构建下载互联网,HTTPS,文件大小、构建容器时的磁盘抖动、层缓存、复杂的构建编排等)

鉴于我们所知道的一切,我认为这可能会以 Dupe 或 WontFix 的形式关闭。 我们给出什么用例似乎并不重要。 更新:我很高兴在这里错了。 该提案看起来很开放:)

我们公司转移到了不可知的容器运行时,并且很快也将不得不转移到不可知的图像构建体验。 但这不是讨论这个问题的正确地方,因为消极情绪无济于事。 那应该是一个单独的帖子。

@rdsubhas愿意在您完成后分享链接吗?

@rdsubhas这是一个很好的总结。 由于@cpuguy83认为他可以在涵盖大多数用例的构建过程中添加--mount ,因此该线程看起来不会像 dupe/wontfix 那样关闭。

我想知道的是当前的提案:

  1. 不改变 Dockerfile 语法
  2. 不会使构建更依赖于它们当前的主机

关于这个想法还有哪些反对意见? 如果没有,也许我们应该开始讨论--mount机制的实现细节。

为了重新执行构建已经依赖于主机且不可复制的论点,我提供了具有此属性的 Dockerfile 片段列表:

# Install different software depending on the kernel version of the host
RUN wget http://example.com/$(uname -r)/some_resource
# example.intranet is only accessible from specific hosts
RUN wget http://example.intranet/some_resource
# get something from localhost
RUN wget http://localhost/some_resource
# gcc will enable optimizations supported by the host's CPU
RUN gcc -march=native .....
# node:latest changes as time goes by
FROM node
# ubuntu package lists change as time goes by
RUN apt-get update
# install different software depending on the docker storage driver
RUN if [ $(mount | head -n 1 | awk '{print $5}') == "zfs" ]; then .....; fi

老实说,如果我们只添加--mount并让用户处理缓存失效( --no-cache ),我想我们会没事的。 我们可能希望从 CLI 中查看更细粒度的缓存控制,而不是全部或全部,但这是一个单独的主题。

我的用例

一段时间以来,我一直面临类似的问题,但我选择增加图像的大小,直到最终确定解决方案。 如果有人找到更好的解决方法,我将尝试在这里描述我的场景。

状况

  1. CircleCI 具有 ssh 密钥,可在构建期间下载所有内部依赖项
  2. GitHub 托管内部依赖项,其他依赖项可在构建期间从映像中下载

选项

  1. 在构建期间使用--build-arg传递令牌(强烈建议不要这样做)。 这是一个非常有吸引力且简单的选择,因为“它可以正常工作”而无需任何附加步骤。
  2. 下载所有依赖项并将它们添加到构建上下文中。 不幸的是, ADDCOPY是在不同的层中执行的,所以我被前一层的数据困住了。

在某些情况下,我的一些图像的大小增加了一倍以上,但目前总体大小是可以忍受的。 我认为有一个 PR(我似乎找不到它)从构建历史记录中删除构建时间参数,但由于缓存问题 irrc,这是不可接受的。
我很高兴听到那里正在使用任何其他解决方法。

@misakwa我们可能会在 1.14 版本中支持机密。

听到@cpuguy83 真是令人兴奋。 我会留意它什么时候发布。 它肯定会简化我的一些工作流程。

我们可能会在 1.14 版本中支持机密。

它是否也适用于映射其他类型卷的构建时映射,例如yarn-cache

顺便说一句,有一种使用 docker-compose 构建生产映像的有趣方法,我发现它有效且非常有效:

所以你有这样的撰写文件docker-compose.build.yml

services: 
  my-app:
    image: mhart/alpine-node:7.1.0
    container_name: my-app-build-container # to have fixed name
    volumes:
    - ${YARN_CACHE}:/root/.cache/yarn # attach yarn cache from host
    - ${HOME}/.ssh:/.ssh:ro    # attach secrets
    - ./:/source
    environment: # set any vars you need
     TEST_VAR: "some value"    
    ports:
    - "3000"
    working_dir: /app/my-app # set needed correct working dir even if if doesn't exist in container while build type
    command: sh /source/my-app.docker.build.sh # build script

1)您使用 docker compose 构建容器:

$ docker-compose -f docker-compose.build.yml up --force-recreate my-app

它创建容器并运行 shell 构建脚本my-app.docker.build.sh ,我不使用Dockerfile并在构建脚本中执行所有操作:

  • 安装所需的操作系统包
  • 复制所需的源代码(从映射的/source文件夹)
  • 安装依赖项
  • 如果需要,构建/编译/测试
  • 删除目标环境工作不需要的包和东西(以减小最终图像大小)

然后从容器创建图像,替换 CMD 以在目标环境中运行:

docker commit -c "CMD npm run serve" my-app-build-container my-app-build-image:tag

因此,您的图像已准备就绪,使用了外部纱线缓存和外部密钥,这些密钥仅在构建时可用。

@whitecolor是的,有效:) 除了一件事: docker build在上传构建上下文方面非常有效。 不幸的是,挂载的源卷不适用于远程 docker 守护进程(例如,用于低功率/带宽笔记本电脑的云上的 docker-machine)。 为此,我们必须执行繁琐的docker rundocker cpdocker run等一系列 docker 命令,然后对最终图像进行快照,但它真的很hacky。

将这个正式的一部分作为 docker build 的一部分,并使用分层和构建上下文真的很有帮助😄

@rdsubhas是的,你是对的

@whitecolor这是一个非常简单有效的解决方案。 我只是将一个项目的 30-40 分钟构建时间缩短到大约 5 分钟。 我期待有一个 --mount on build 功能的可能性,但现在这个解决方案真的解除了我的管道阻塞。

这是我为 issue #17745 留下的评论,我知道该评论已关闭但未标记为重复。 似乎我对后一点是错误的:我承认我已经习惯了像 Bugzilla 这样的系统,它明确地将某些东西标记为“已解决的重复”,并在错误的顶部描述区域中显示这样的内容。 我不是读心术。 (所以我很抱歉@graingert ,我几乎不知道,因此没有必要用 20pt 字体对我大喊大叫——这太过分了。)


就我而言,这在 Debian 系统上会很有用:将/var/cache/apt挂载为一个卷,这样您就不会一遍又一遍地重新下载相同的 .deb 文件。 (真正的“无限”互联网配额根本不存在,尤其是在澳大利亚,即使有,等待下载也是浪费时间。)

或者在另一种情况下,您正在进行构建,但它也会生成测试报告,例如故障列表和代码覆盖率报告,您不需要随图像一起发布,但它们是有用的人工制品。 当 CI 服务器构建映像以供 CI 服务器拾取和托管时,这些可以写入卷。

或者今晚,我正在为自己做一些基于 Gentoo 的图像,我想从主机挂载/usr/portageDockerfile不难意识到,“嘿, /usr/portage (在容器中)是空的,没问题我会抓住它”在没有安装卷的情况下运行,或者,它只是按原样使用卷,节省了获取新副本的时间。

在 Bourne shell 脚本中添加这些智能是一个微不足道的 if 语句……如果挂载卷的底层逻辑首先存在。 现在,对于我的 Gentoo 镜像,我每次构建时都必须拉/usr/portage (幸运的是镜像在我的 LAN 上),这意味着这一步完成需要等待几分钟。

为什么这是一个有价值的提议有很多原因,我怀疑#7115 中提议的嵌套构建是否会在上述情况下有所帮助。


@whitecolor有一个有趣的方法,但如果这样做,我还不如使用一个完全在 Docker 系统外部的Makefile来实现构建。

@sjlong​​land我不是在对你大喊大叫,我是在填一个大的“已解决重复”通知

我正在使用 docker 和 docker-compose 为我们的基础架构构建多个容器。 容器是微服务,大部分是用 nodeJS 编写的,但是有一个用 Java 编写的微服务,使用 maven 框架。
每次我们重建java容器,都会从Maven下载几十个依赖; 这需要几分钟。 然后代码在大约 15 秒内构建。

这非常难看,它对我们的 CI 策略影响很大。

在这种情况下,具有构建依赖项的卷是否丢失或为空并不重要,因为在这种情况下,依赖项将被下载。 再现性不受影响。

我知道存在安全问题,因为我可以篡改依赖项并在其中注入讨厌的代码; 恕我直言,可以通过不允许在 docker-hub 或 docker-store 上发布使用“构建卷”构建的图像来轻松规避。
为了不同地说明这一点,企业使用和个人使用 docker 之间应该有范围的区别。

@stepps检查https://pypi.python.org/pypi/shipwright而不是 docker-compose

我一直在关注这个线程一段时间,为自己寻找一个好的解决方案。 为了以最小的努力以灵活的方式构建最小的容器,我真的很喜欢 @edannenberg 的https://github.com/edannenberg/gentoo-bb

  • 它将构建时依赖项与运行时依赖项分开
  • 构建是在容器中完成的,并且是隔离的、干净的和可重复的
  • 处理图像和构建顺序之间的依赖关系

它基于使用Gentoo 的portage 和emerge,所以@sjlong​​land你可能会喜欢它用于基于Gentoo 的图像。 Dist 文件和二进制包被缓存,因此不需要下载或再次构建它们,从而使重建速度更快。 它具有轻松自定义构建过程的钩子。 安装 3rd 方软件很容易,例如使用 git 克隆一个 repo 然后构建它,只保留最终映像中的构建。 它模板化了 Dockerfile。

一个简单的例子是figlet是: -

构建.conf:

IMAGE_PARENT="gentoobb/glibc"

Dockerfile.template:

FROM ${IMAGE_PARENT}
ADD rootfs.tar /
USER figlet
CMD ["gentoo-bb"]
ENTRYPOINT ["figlet"]

构建.sh

PACKAGES="app-misc/figlet"

configure_rootfs_build() {
        useradd figlet
}

我喜欢@whitecolor的解决方案,它很简单,只使用 Docker 技术,然后是简单的 shell 脚本或任何你想使用的东西。 我正在使用 gentoo-bb,因为它更完整。 Shipwright 看起来不错,具有更多以开发人员为中心的功能,例如处理分支。 https://github.com/grammarly/rocker似乎也很有趣。 谢谢大家分享。

只是另一个声音加入了这堆声音。 如果我们可以在构建时挂载本地卷,我们非常复杂的开发环境将变得更加简单。

一种解决方法是在构建期间运行一个公开本地文件的 http 服务器,然后使用 curl/wget 等将文件放入 docker 构建中。 但我真的希望这样的黑客行为是不必要的。

另一个用例.. 我想构建 docker 镜像来构建一个专有操作系统,它有 10 个不同的版本。 安装媒体 > 80GB,所以我不能把它复制到 docker 构建环境中。 绑定安装会更可取。

另一个:我的项目使用在存储库中分发 Dockerfile,以便从容器中的源构建。 目前,我们从 github 拉取另一个 git clone 到容器中。 有浅克隆等等,但仍然......

因此,我刚刚在 rhel7 构建主机上测试了 [1],而 Red Hat 的 docker 守护进程的构建确实具有 -v 构建选项。 我还没有在 CentOS/Fedora 上测试过,但可以想象 Fedora/CentOS 可能也有。 值得测试。 此外,RHEL 开发人员订阅现在是免费的 [2]:

@fatherlinux在 Fedora 下 `docker build -v' 也可用。

@fatherlinux CentOS 7 版本包含它。

+1 我认为这将是添加到官方 docker 中非常有用的功能。

刚刚更新了 centos 和 linuxmint(现在运行 17.03.1-ce),我在这里遗漏了什么吗? 我看不到选项-v

薄荷糖

$ docker build --help

Usage:  docker build [OPTIONS] PATH | URL | -

Build an image from a Dockerfile

Options:
      --build-arg list             Set build-time variables (default [])
      --cache-from stringSlice     Images to consider as cache sources
      --cgroup-parent string       Optional parent cgroup for the container
      --compress                   Compress the build context using gzip
      --cpu-period int             Limit the CPU CFS (Completely Fair Scheduler) period
      --cpu-quota int              Limit the CPU CFS (Completely Fair Scheduler) quota
  -c, --cpu-shares int             CPU shares (relative weight)
      --cpuset-cpus string         CPUs in which to allow execution (0-3, 0,1)
      --cpuset-mems string         MEMs in which to allow execution (0-3, 0,1)
      --disable-content-trust      Skip image verification (default true)
  -f, --file string                Name of the Dockerfile (Default is 'PATH/Dockerfile')
      --force-rm                   Always remove intermediate containers
      --help                       Print usage
      --isolation string           Container isolation technology
      --label list                 Set metadata for an image (default [])
  -m, --memory string              Memory limit
      --memory-swap string         Swap limit equal to memory plus swap: '-1' to enable unlimited swap
      --network string             Set the networking mode for the RUN instructions during build (default "default")
      --no-cache                   Do not use cache when building the image
      --pull                       Always attempt to pull a newer version of the image
  -q, --quiet                      Suppress the build output and print image ID on success
      --rm                         Remove intermediate containers after a successful build (default true)
      --security-opt stringSlice   Security options
      --shm-size string            Size of /dev/shm, default value is 64MB
  -t, --tag list                   Name and optionally a tag in the 'name:tag' format (default [])
      --ulimit ulimit              Ulimit options (default [])
$ cat /etc/lsb-release 
DISTRIB_ID=LinuxMint
DISTRIB_RELEASE=18
DISTRIB_CODENAME=sarah
DISTRIB_DESCRIPTION="Linux Mint 18 Sarah"
$ docker version
Client:
 Version:      17.03.1-ce
 API version:  1.27
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Fri Mar 24 00:45:26 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.03.1-ce
 API version:  1.27 (minimum version 1.12)
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Fri Mar 24 00:45:26 2017
 OS/Arch:      linux/amd64
 Experimental: false

在centos 7上

# docker build --help

Usage:  docker build [OPTIONS] PATH | URL | -

Build an image from a Dockerfile

Options:
      --build-arg list             Set build-time variables (default [])
      --cache-from stringSlice     Images to consider as cache sources
      --cgroup-parent string       Optional parent cgroup for the container
      --compress                   Compress the build context using gzip
      --cpu-period int             Limit the CPU CFS (Completely Fair Scheduler) period
      --cpu-quota int              Limit the CPU CFS (Completely Fair Scheduler) quota
  -c, --cpu-shares int             CPU shares (relative weight)
      --cpuset-cpus string         CPUs in which to allow execution (0-3, 0,1)
      --cpuset-mems string         MEMs in which to allow execution (0-3, 0,1)
      --disable-content-trust      Skip image verification (default true)
  -f, --file string                Name of the Dockerfile (Default is 'PATH/Dockerfile')
      --force-rm                   Always remove intermediate containers
      --help                       Print usage
      --isolation string           Container isolation technology
      --label list                 Set metadata for an image (default [])
  -m, --memory string              Memory limit
      --memory-swap string         Swap limit equal to memory plus swap: '-1' to enable unlimited swap
      --network string             Set the networking mode for the RUN instructions during build (default "default")
      --no-cache                   Do not use cache when building the image
      --pull                       Always attempt to pull a newer version of the image
  -q, --quiet                      Suppress the build output and print image ID on success
      --rm                         Remove intermediate containers after a successful build (default true)
      --security-opt stringSlice   Security options
      --shm-size string            Size of /dev/shm, default value is 64MB
  -t, --tag list                   Name and optionally a tag in the 'name:tag' format (default [])
      --ulimit ulimit              Ulimit options (default [])
# docker version
Client:
 Version:      17.03.1-ce
 API version:  1.27
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Mon Mar 27 17:05:44 2017
 OS/Arch:      linux/amd64
# cat /etc/centos-release
CentOS Linux release 7.3.1611 (Core) 

@wilfriedroset在 CentOS 7 中,非官方 Docker 软件包提供了该选项。 我认为它是 EPEL 存储库的一部分。

谢谢@nathanjackson。 我们在官方版本中有此功能的预计到达时间吗?

@wilfriedroset AFAIK,没有 ETA,因为(多次)决定此功能不应该在官方 docker 中以保持“构建可移植性”。 也就是允许你的 Dockerfiles 在任何地方运行,包括 Docker 构建服务。

以我的经验,有限的构建可移植性是客户真正想要的。 他们想要建立一个构建环境/农场,并确保始终可以在该环境中重建构建。 -v 构建选项不会以任何方式阻止这种情况。

例如,如果您使用 NFS 挂载,只需确保所有构建服务器的 fstab 中都有该挂载,并且您的构建将在场中的任何地方顺利完成。

在 RHEL 7.3 上
````
[ root@rhel7 ~]# docker build --help

用法:docker build [OPTIONS] PATH | 网址 | -

从 Dockerfile 构建镜像

选项:
--build-arg value 设置构建时变量(默认 [])
--cgroup-parent string 容器的可选父 cgroup
--cpu-period int 限制 CPU CFS(完全公平调度器)周期
--cpu-quota int 限制 CPU CFS(完全公平调度器)配额
-c, --cpu-shares int CPU 份额(相对权重)
--cpuset-cpus 字符串允许执行的 CPU (0-3, 0,1)
--cpuset-mems string 允许执行的 MEM (0-3, 0,1)
--disable-content-trust 跳过图像验证(默认为 true)
-f, --file string Dockerfile 的名称(默认为 'PATH/Dockerfile')
--force-rm 总是删除中间容器
--help 打印用法
--isolation string 容器隔离技术
--label value 为图像设置元数据(默认 [])
-m, --memory string 内存限制
--memory-swap string 交换限制等于内存加上交换:'-1' 启用无限交换
--no-cache 构建镜像时不使用缓存
--pull 总是尝试拉取更新版本的镜像
-q, --quiet 禁止构建输出并在成功时打印图像 ID
--rm 成功构建后删除中间容器(默认为 true)
--shm-size string /dev/shm 的大小,默认为 64MB
-t, --tag value 名称和可选的 ' name:tag ' 格式的标签(默认 [])
--ulimit 值 Ulimit 选项(默认 [])
-v, --volume value 设置构建时绑定挂载(默认 [])
```

CI 构建节点项目的另一个用例是在构建所有图像时共享 CI 的yarn缓存。

+1:一次又一次安装node_modules真的很糟糕,尤其是对于nodejs微服务
我正在尝试用 nfs 解决这个问题,我认为“可重复”不是不实现此功能的好理由......

这似乎在 #31257 和 #32063 合并后变得更加重要。

看看#32507

@fatherlinux你能解释一下当你可以在 Dockerfile 中使用 COPY 命令时构建可移植性是如何工作的吗? 我有一个问题,我想避免大文件的副本数量(出于时间复杂性的原因),并且正在寻找一个构建时只读选项来与容器共享文件。

@arunmk @cpuguy83完全正确。 这个想法是你真的不想在构建时将数据复制到容器中。 这可以使它非常大。 我们只希望在构建时可用数据。 如上所述,您可以在 Red Hat 的 docker 守护程序版本中执行 -v 绑定挂载,它允许您获得可用数据,但它现在是只读的(上周烧死了我)。

因此,如果您今天需要它,请查看 Fedora、CentOS 或 RHEL,您可以在构建时装入只读数据副本...

而且,如果您需要在构建场内具有可移植性,我建议您使用 NFS 或类似的......

如果您不关心复制它,而只关心将其放入最终图像中,您可以使用多阶段构建来处理这个问题。

一个人为的例子:

FROM fatImage AS build
COPY bigData /data
RUN some_stoff /data

FROM tinyImage
COPY --from=build /data/result

感谢@fatherlinux 的澄清
@cpuguy83感谢您提供详细信息。 让我为我的问题添加更多细节,这可能不常见:我有一个生成 3.3GB 文件的构建系统。 这被添加到构建在 docker 容器中的 RPM 中。 所以会产生两个副本:一个从构建系统到 docker 容器,一个从 docker 容器到 RPM。 现在,我无法避免第二个副本。 我正在考虑避免第一个副本,但看起来这也是不可能的,即使是多阶段构建。
我可以理解,如果重复使用大文件,多阶段复制将复制运行的次数减少到'1'。 我用过一次,想把数字减到“0”。 我是否理解这是不可能的?

@arunmk不管它必须从客户端复制到构建实例。

@cpuguy83感谢您的澄清。 看来我现在必须承担开销。 那是具有原子性吗?

@fatherlinux

我尝试了您所说的,在 RHEL7 上使用 -v 尝试在构建期间只读挂载目录,但出现此错误:

docker build 不支持卷。 请仅使用绑定挂载。

这仅适用于来自 RHEL 的 docker 包,而不是来自 Docker 的包。 补丁未被上游接受。

@fatherlinux

我尝试了您所说的,在 RHEL7 上使用 -v 尝试在构建期间只读挂载目录,但出现此错误:

docker build 不支持卷。 请仅使用绑定挂载。

@fcntl

如错误所述,您需要使用绑定,您可能使用-v /something而不是/hostsomething:/containersomething

@thebigb或许还有其他人,我们已经建立了一个基础设施,以便能够在 docker 构建期间使用 ccache。 如果它对您有帮助,我们已经在https://github.com/WebHare/ccache-memcached-server上发布了它,尽管理想情况下解决这个问题可能会使它过时。

我正要补充,我真正需要的一个用例是 ccache。 我希望能够在 docker 映像构建期间挂载我的 ccache 缓存——在映像本身中没有任何意义。 @unilynx我会看看你的解决方法——好时机!

只是另一个声音。

我的用例:目前我使用rockerMOUNT命令来共享/root/.cache/var/cache/apk目录。

出于某种原因,我对 apk 包和 pip 包的网络访问速度非常(非常,非常)慢。 任何重建都会使该过程非常耗时。 使用此构建时MOUNT功能使事情变得容易得多。

@embray @roxma看看https://github.com/moby/moby/issues/32507是否可以解决您的用例; 欢迎反馈

随着多阶段构建的引入,我发现为 Maven 的本地缓存指定卷挂载是至关重要的。

@gim913这不是您参与任何社区的方式。 如果您想做出贡献,请查看此处链接的现有提案,看看是否有任何提案可以解决您的用例。

@gim913在将 docker 集成到各种发行版的这个阶段,改变环境(即完全放弃 docker)似乎比改变你的“操作系统”更具破坏性(我假设你的意思是从不同的 Linux 发行版切换到显然包括的 RedHat 版本) -v?)

使用 RedHat 的 docker 版本不是更容易吗? 也许这里有人可以将您指向相关的补丁/分叉/提交,以在构建中获取“-v”选项。

@unilynx

我正在查看一些使用 wget 并到达这里的示例……我的用例类似……我想解压缩一个大的 tarball 并运行它。 我不想乱扔带有 tarball 的 docker 文件或浪费时间从本地 Web 服务器执行 wget。 使用 docker compose 进行安装似乎是在构建时做的合理的事情。 如果看起来不错,请合并 Puneeth 的更改 :-)

我预编译 python 轮子并希望将它们安装在容器中而不复制它们并制作我真的不需要的层,或者必须以某种方式尝试挤压。 第 1 天,我已经在调查rocker 😢 😢 😢

这将很容易添加并且非常有用(或挂载命令,请参见rocker再次)。 围绕这个或类似的缺失功能编写脚本(在社区中)花了多少时间?

@awbacker Multi-stag build 很好地解决了这个问题,您可以在其中执行类似的操作

FROM something AS my_wheels
RUN compile_all_the_things

FROM something
COPY --from my_wheels /wherever
RUN do_stuff_with_wheels

第一部分仅在发生变化时运行。 它的缓存也可以在其他构建/dockerfiles 之间共享。
这使得整个构建独立。

还有一个提案允许RUN --mount挂载规范会告诉它从my_wheels构建目标挂载一个东西,而不是复制它。

就像@kenyee一样,这可以从构建上下文中挂载一些东西,在 17.07-experimental 中只根据需要增量发送。

@cpuguy83这在实践中不起作用——至少对于 Gradle Java 构建而言。 我有一个基础 Docker 映像,其中预先缓存了 Gradle Jar 文件,但是源代码的 Gradle 构建是触发将所有依赖项下载到缓存中的原因。

@cpuguy83多级不允许从结果图像中删除复制的轮子,这就是@awbacker所说的。 因此 /wherever 文件夹中的内容将被缓存并增加图像大小。

@BryanHunt所以你的构建过程的一部分是下载deps? Gradle 肯定必须提供一种方法来缓存这些而不经过实际构建吗?

@cpuguy83是的,deps 作为构建的一部分下载。 与Maven基本相同。 供参考: https ://github.com/gradle/gradle/issues/1049

某处有用于构建安装的 PR 吗?

@graingert在这里

👍为此。 在 Lunar Way,我们希望在单个 Docker 构建中完成完整的“构建 -> 测试 -> 构建生产映像”过程,以便从 CI 服务器中删除构建和测试依赖项。 通过多阶段构建,我们可以做到这一点,但我们无法在构建过程中从中间容器中获取测试结果。 因此,我们现在必须分两步进行 - 使用单独的 Dockerfile 构建测试映像,运行它,然后如果测试成功,则仅继续进行构建 prod 映像步骤。

docker build 上的 -v 选项将允许我们将测试结果存储在从 CI 服务器安装的文件夹中,并且无需当前的两步过程。

@tbflw默认情况下,Docker 构建在构建不成功后不会删除中间容器。 因此,如果测试失败,您可以从中获取测试结果。

拜托,我们也非常非常需要这个功能! 诉诸其他工具,例如带有临时补丁的 Rocker 或 fork docker,比打破“构建可移植性”的福音概念要丑陋得多。

@BryanHunt @stepps @yngndrw其他人 @awhitford
缓存构建依赖项的一种方法是使您的构建像文档中的示例多阶段 go buildpython onbuild Dockerfile 一样工作
是我制作的一个似乎适用于 Maven 的示例。 我会在这里复制它。

FROM maven
WORKDIR /usr/src/app
# /root/.m2 is a volume :(
ENV MAVEN_OPTS=-Dmaven.repo.local=../m2repo/
COPY pom.xml .
# v2.8 doesn't work :(
RUN mvn -B -e -C -T 1C org.apache.maven.plugins:maven-dependency-plugin:3.0.2:go-offline
COPY . .
RUN mvn -B -e -o -T 1C verify

FROM openjdk
COPY --from=0 /usr/src/app/target/*.jar ./

它需要进行设置,以便在复制代码库的其余部分之前下载依赖项。还要确保存储工件的位置不在 VOLUME 中

@sixcorners这对 Gradle 不起作用

@BryanHunt此 Dockerfile 或此方法不适用于 gradle? cpuguy83 询问是否有一种方法可以在不实际执行构建的情况下下载依赖项。 您链接到解决依赖项任务。 您不能只添加 build.gradle 文件并运行该任务吗?

@sixcorners当您有许多模块时,您必须复制目录结构以及构建文件和属性文件。 我想这是可以做到的,但我认为这很容易出错。

@sixcorners的多阶段是一个有趣的技巧,我已经看到它用于不同的包管理器(例如 npm、composer)。

但是有一个问题,每当更改阶段 0 图像中的依赖项列表COPY pom.xml都会导致图层被丢弃,因此整个缓存都消失了。 这意味着每当开发人员更改 pom 中的任何内容(评论,1kBytes 依赖项)时,都必须再次重新下载整个缓存。

对于构建映像然后运行依赖项不断变化的测试的 CI 机器,即必须重新下载成千上万个包(从代理或上游)并且使重建非常缓慢。 安装为卷的基于本地文件的缓存要快得多。

当开发人员迭代构建映像时,这也是一个问题,特别是在他们连接速度较慢的情况下。 尽管可以为它设置一个本地 Nexus 实例和 http_proxy,但这有其他副作用(例如通过 Nexus 引导任何 http 请求)。

多阶段是一个很好的解决方法,但它并不理想。

我们即将尝试的一个解决方案是通过构建我们的共享库并保留依赖缓存来构建图像。 然后这个镜像将成为我们应用程序的构建镜像。 这并不理想,但我们认为值得一试。

但是有一个问题,每当更改依赖项列表时,第 0 阶段图像中的 COPY pom.xml 都会导致图层被丢弃,因此整个缓存都消失了。 这意味着每当开发人员更改 pom 中的任何内容(评论,1kBytes 依赖项)时,都必须再次重新下载整个缓存。

@hashar请注意, COPY --from功能不仅限于构建阶段; 来自Dockerfile 参考

可选地COPY接受一个标志--from=<name|index> ,该标志可用于将源位置设置为先前的构建阶段(使用FROM .. AS <name>创建),而不是发送的构建上下文由用户。 该标志还接受为以FROM指令开始的所有先前构建阶段分配的数字索引。 _如果找不到具有指定名称的构建阶段,则尝试使用具有相同名称的映像。 _

这允许您为您的依赖项_build_一个图像,标记它,并使用它来复制您的依赖项。 例如:

FROM maven
WORKDIR /usr/src/app
# /root/.m2 is a volume :(
ENV MAVEN_OPTS=-Dmaven.repo.local=../m2repo/
COPY pom.xml .
# v2.8 doesn't work :(
RUN mvn -B -e -C -T 1C org.apache.maven.plugins:maven-dependency-plugin:3.0.2:go-offline
COPY . .
RUN mvn -B -e -o -T 1C verify
docker build -t dependencies:1.0.0 .

并为您的依赖项指定使用dependencies:1.0.0图像;

FROM openjdk
COPY --from=dependencies:1.0.0 /usr/src/app/target/*.jar ./

或者(只是一个非常基本的测试示例);

$ mkdir example && cd example
$ touch dep-one.jar dep-two.jar dep-three.jar

$ docker build -t dependencies:1.0.0 . -f -<<'EOF'
FROM scratch
COPY . /usr/src/app/target/
EOF

$ docker build -t myimage -<<'EOF'
FROM busybox
RUN mkdir /foo
COPY --from=dependencies:1.0.0 /usr/src/app/target/*.jar /foo/
RUN ls -la /foo/
EOF

在构建的输出中,您将看到:

Step 4/4 : RUN ls -la /foo/
 ---> Running in 012a8dbef91d
total 8
drwxr-xr-x    1 root     root          4096 Oct  7 13:27 .
drwxr-xr-x    1 root     root          4096 Oct  7 13:27 ..
-rw-r--r--    1 root     root             0 Oct  7 13:26 dep-one.jar
-rw-r--r--    1 root     root             0 Oct  7 13:26 dep-three.jar
-rw-r--r--    1 root     root             0 Oct  7 13:26 dep-two.jar
 ---> 71fc7f4b8802

我不知道是否有人提到过这个用例(我简要搜索了该页面),但是将 SSH 身份验证套接字安装到构建容器中将使通过私有 git 存储库部署的依赖项的使用变得更加容易。 Dockerfile 中关于在非最终构建阶段复制密钥等方面的样板文件的需求将减少。

buildkit 原生支持 git
https://github.com/moby/buildkit

解决。
创建 bash 脚本(~/bin/docker-compose 或类似):

#!/bin/bash

trap 'kill $(jobs -p)' EXIT
socat TCP-LISTEN:56789,reuseaddr,fork UNIX-CLIENT:${SSH_AUTH_SOCK} &

/usr/bin/docker-compose $@

在 Dockerfile 中使用 socat:

...
ENV SSH_AUTH_SOCK /tmp/auth.sock
...
  && apk add --no-cache socat openssh \
  && /bin/sh -c "socat -v UNIX-LISTEN:${SSH_AUTH_SOCK},unlink-early,mode=777,fork TCP:172.22.1.11:56789 &> /dev/null &" \
  && bundle install \
...
or any other ssh commands will works

然后运行docker-compose build

将另一个用例扔到一堆。 我使用 Docker for Windows 来生成一个文件系统,用于在一个容器中构建嵌入式 linux 系统,我想在其他容器的构建步骤中与它们共享。 我与这个容器交互,更改配置和重建等,因此在 Dockerfile 中执行构建并使用多阶段构建并不是一个非常合适的选择,因为我会丢失增量构建。 我想缓存我以前的构建工件,因为它需要大约 1.5 小时来完成一个干净的构建。 由于 Windows 处理符号链接的方式,我无法构建到主机安装的卷中,因此我使用命名卷。 理想情况下,我想在其他图像的构建步骤中共享这些命名卷; 因为目前我必须创建一个构建输出的 tar(大约 4gb),然后做一个 docker 副本,以使其在 Windows 主机上可用,以供后续构建。

在 python 的情况下,当我们pip install package时,它及其依赖项被下载到缓存文件夹,然后安装到站点包中。
作为一个好的做法,我们使用pip --no-cache-dir install package来不在当前层存储垃圾/缓存。 但为了获得最佳实践,最好将缓存文件夹置于构建上下文之外。 所以 build time -v 会有所帮助。
上面提到的一些用户使用COPY . /somewhere/in/container/可以用于用户应用程序或文件,但不能用于缓存。 因为 COPY 会再创建一层作为它自己的层,并且在后面的层中删除缓存将没有用。 另一个不好的副作用是,如果在我们使用 COPY 时更改了缓存,则上下文更改并且后续层将失效并被迫重建。

@wtayyeb如果您有仅在需求文件更改时运行pip install ...的 Dockerfile,那么构建时间 -v 似乎并不那么重要,因为需求不会像构建时应用程序那样频繁地更改。

@wtayyeb您可以使用多阶段 Dockerfile 来同时拥有缓存和精简映像。 也就是说,使用安装程序映像将 python 安装到某个目录中,然后对于您的最终映像,使用 COPY --from 仅传输必要的 python 文件,而不需要任何安装工件甚至 pip 本身。

@manishtomar ,谢谢,是的,不是的! 在干净的情况下,所有依赖项都会再次下载并构建并转换为轮子并缓存,然后安装到目标环境中。 因此,如果一个人在那里提出要求,那就是一次工作。 但是,如果更新了一个微小的依赖项,则所有依赖项都必须重新下载、重新构建、重新轮换和重新缓存才能使用。
当使用 CI 在多个作业的矩阵中构建和测试您的库和应用程序时,将上述工作乘以 CI 服务器中的并发作业数量,即使使用 SSD,iowait 也会提高到 3 秒以上,平均负载也会超过 15。 (这些数字对于 2 个并发构建和具有约 20 个依赖项的应用程序是真实的)我认为 pip 缓存以正确的方式进行,避免重新下载、重新构建和重新启动准备好的包。 并且没有 bind -v 我们会浪费时间和服务器资源。

@ibukanov ,谢谢。 我正在使用多阶段 Dockerfile 来构建我的应用程序包并在以后使用它们。 如果我只有一个 Dockerfile 并且想要多次构建它会有所帮助,但是如果有多个 Dockerfile 并且每个 Dockerfile 都是针对 python 版本(目前为 2.7、3.6)构建的,并且还有几个需要的 c 扩展为选定的基础映像构建? 上一段呢?

@thaJeztah你的建议很棒,它会为我们节省一些时间,但是在构建缓存的情况下,我们真的不想从另一个图像中复制任何东西。
为什么我们不能在不复制的情况下访问另一个图像?

@thedrow我的示例是当前存在的功能; 查看RUN --mount提案(https://github.com/moby/moby/issues/32507),它可能更适合您的用例

阅读上面的帖子,我看到很多人试图找到解决 docker 构建过程中基本功能差距的问题。 如果不必将主机挂载与图像挂载混为一谈,我认为没有任何令人信服的论点来自可移植性的基础——坦率地说,这些论点是似是而非的和懒惰的。

我也是 gentoo 容器用户,并从https://github.com/moby/moby/issues/3156重定向,这是缺少此功能的完全有效的用例。

我真正想要的是能够在构建时挂载另一个图像的内容,这样我就不会膨胀我的图像。

@kbaegis听起来与https://github.com/moby/moby/issues/32507中提出的功能完全匹配

当然。 那个在积压工作中只是一个未实现的 P3 一年而不是 3 年。

对于这个基本功能,看起来https://github.com/projectatomic/buildah实际上很快就会超过 docker build。 我想一旦发生这种情况,我就会切换我的管道。

@kbaegis你来这里是为了加入这个讨论吗? 您描述了一个_exactly_匹配不同提案的用例;

我真正想要的是能够在构建时挂载另一个图像的内容,这样我就不会膨胀我的图像。

它是开源的,事物不会神奇地存在。

我想在讨论中添加什么?

简而言之,我正在从这个工具集继续前进。 我确信这对开发团队来说是有价值的信息,因为我确信我并不孤单。

支持此用例(以及提供此功能的任何可靠变通方法)的极速和低优先级迫使我使用其他工具,并且由于缺少功能,我放弃了此构建管道。

我有一个(重新散列,我敢肯定)用例要添加。 #32507 可能更适合这个。

我正在为一些生物信息学管道构建一个 docker 映像。 一些工具需要在编译/安装之前存在一些数据库(请不要问,这不是的代码)。 这些数据库的最小重量为 30GB。

在运行时,我当然打算将这些数据库挂载-v卷。 不幸的是,在构建过程中,如果不“烘烤”它们,我就无法做到这一点,从而导致图像尺寸相当大。

@draeath看看https://github.com/grammarly/rocker 。 它已经支持一个可爱的 MOUNT 指令。

@draeath也可以查看 Buildah,它默认支持挂载,因为它的设置更像是一个编程工具。 还支持使用 Dockerfile 挂载:

https://github.com/projectatomic/buildah

谢谢@fatherlinux@lig - 这将帮助我完成我的任务。 不过,我仍然认为我不应该在项目之外做这件事,并且仍然希望看到这个和 #32507 实施;)

我通过一些谷歌搜索来到这里,要求相同的功能,在“docker build”时间而不是“docker run”时间的卷。

我们有一个包含 CPU 的嵌入式系统。 制造商提供工具来组成系统映像,然后将映像传输到 CPU。 这个工具对我来说是第 3 方,我无法更改它。 制造商也不太可能应我的要求对其进行更改。

我想构建一个 docker 映像,它首先通过“构建固件映像”,然后能够生成仅将固件映像推送到新下线 PCB 的容器。 一个 Dockerfile 可能看起来像:
- - - - - [ 剪这里 ] - - - - -
FROM base-image 作为构建器
复制源代码
运行构建源

FROM base-image 作为 flasher
COPY --from=builder build-artifacts
运行 cpu-build-and-flash --build-only
- - - - - [ 剪这里 ] - - - - -
不幸的是,cpu-build-and-flash 步骤需要通过 USB 总线访问目标设备,即使它不会将固件映像推送到设备。 因此,我需要从“docker run”命令中获取“-v /dev/usb/bus:/dev/usb/bus”,并将其放入构建中。

很明显,目前这是不可能的。

我要进行的解决方法是通过“docker container commit”将容器提交到图像来手动创建闪烁的图像。 我宁愿在构建时安装 USB 总线。

感兴趣的人可以更新一下:我最近用 buildah 成功地重建了我的整个管道。 我目前已经让两个构建管道并行运行,并且 oci/buildah 管道正在生成较小的图像(特别是在我的情况下,通过用另一个挂载掩盖它来删除 /usr/portage)。

最后这个功能在这里: https ://github.com/docker/docker-py/issues/1498

但我想要构建缓存的 RW 卷

2018 年 4 月 28 日星期六 17:29 Коренберг Марк, notifications @github.com 写道:

最后这个功能在这里:docker/docker-py#1498
https://github.com/docker/docker-py/issues/1498


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看
https://github.com/moby/moby/issues/14080#issuecomment-385188262或静音
线程
https://github.com/notifications/unsubscribe-auth/AAZQTJodLCCzyDdPFtNiIUZ_z85YvLWbks5ttJjagaJpZM4FIdOc
.

我还希望看到此功能(具有写入功能),以便可以在 CI 管道中的多阶段构建过程中导出单元测试结果文件。 为了保持构建可移植性的精神,如果未提供 -v 开关,则该文件将简单地在该阶段的测试映像内部写入。

理想的目标是构建一次,测试一次,并且仍然将结果文件提供给主机系统,即使在测试失败的情况下(尤其是在事件中),停止构建。

是的,请。 一整天。

不完全相关,但我们正在迁移部署基础架构的一部分,并且需要一种在构建后从映像复制文件的方法。 以下是诀窍:

docker build -t x .
ID=$(docker create x)
docker cp $ID:/package.deb .
docker rm $ID

它应该在引入多阶段 docker 文件时已经添加。 最终每个人都会在开始运行单元测试作为多阶段 docker 文件中的一个阶段时面临这个问题,特别是在 CI 构建管道的情况下。 我们也面临这个问题,我们必须将单元测试报告发布到 VSTS。 已经应用了@hoffa提到的解决方法。 但毕竟这是一种解决方法,使事情变得复杂。

我们是否应该为想要/需要构建缓存的构建时间卷的人提出不同的问题?

@ajbouh是的,可能在https://github.com/moby/buildkit/issues

https://github.com/moby/moby/issues/32507#issuecomment -391685221

2018 年 5 月 23 日星期三 19:22 Akihiro Suda [email protected]写道:

@ajbouh https://github.com/ajbouh是的,可能在
https://github.com/moby/buildkit/issues


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看
https://github.com/moby/moby/issues/14080#issuecomment-391566368或静音
线程
https://github.com/notifications/unsubscribe-auth/AAAcnSqNoVc4j34ElECy53gIfPecQFKfks5t1hlkgaJpZM4FIdOc
.

虽然你不能在构建时添加卷,但你可以添加主机,所以我现在用类似--add-host yum-mirror:$MIRROR_IP的东西构建我所有的 docker 镜像,它提供了一个 yum 镜像,然后我的构建镜像通过一个包装器检测到百胜。 当我的项目每天多次更改依赖项并且我处于脱机状态或连接不良(项目的一部分涉及更新和清理其许多部门)时,这很方便。

我发现 Docker 拒绝解决这个问题令人愤怒。

最近合并了对 buildkit 的实验性支持,其中带有RUN --mount=<opts> <command>的选项。

链接到@cpuguy83注意: https ://github.com/moby/buildkit/pull/442

@glensc @cpuguy83我们什么时候可以期待这个合并功能的发布?

+1

RUN --mount没有容量支持,所以像https://github.com/avsm/docker-ssh-agent-forward这样的东西在构建时仍然是不可能的,解决方案是什么?

docker build --secret终于在 Docker 18.09 中可用https://medium.com/@tonistiigi/build -secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066

我们可以关闭这个问题吗?

据我所知, --secret不适用于缓存用例。

@AkihiroSuda RUN --mount通常看起来可能适合作为此问题的解决方案。

是的,我想RUN --mount=type=cache (用于缓存卷)和--mount=type=secretdocker build --secret (用于秘密卷)几乎涵盖了这个问题。

@AkihiroSuda所以,很高兴看到一个解决原始问题的工作示例

@AkihiroSuda从文章(https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066)我看到了在构建期间使用 mount 的 2 个用例: SecretSSH

[秘密]

docker build --secret id=mysite.key,src=path/to/mysite.key .
RUN --mount=type=secret,id=mysite.key,required <command-to-run>

[SSH]

RUN --mount=type=ssh git clone [email protected]:myorg/myproject.git myproject

还有 2 个其他用例(我记得)没有在文章和本期中解释如何使用:

1) [缓存] RUN --mount=type=cache
2)一般卷(例如,挂载 SSL 证书,或者在构建期间应该使用但不包含在生成的映像中的大卷的情况下,等等......)

一旦用例在运行webpack之前安装yarn工作区

你可以做到这一切..

RUN --mount=type=cache,from=<some image>,source=<path in from image>,target=<target>

您也可以将from=<some image>替换为from=<some build stage>

这是一个人为的例子:

# syntax=docker/dockerfile:1.0.0-experimental
FROM busybox as hello
RUN  echo hello > /hello.txt

FROM scratch
RUN --mount=type=cache,from=busybox,source=/bin,target=/bin --mount=type=cache,from=hello,source=/hello.txt,target=/tmp/hello.txt echo /tmp/hello.txt

这是一些关于此的文档: https ://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md

我同意@AkihiroSuda ,这应该可以处理所有情况......但如果没有,请告诉我们。

@AkihiroSuda @cpuguy83 :不幸的是,当前的实现(docker 18.09 中的 buildkit)存在私有注册表问题。 截至目前,如果您必须通过私有注册表获取图像,则无法使用这些新功能。 在https://github.com/moby/moby/issues/38303 中查看我的测试。

我认为这也可用于 Jenkins 工件,例如,如果我创建一个 Docker 映像并在其中编译一些东西,我想获得一些工件,例如 junit pytest 输出

这将非常有用。 我真的宁愿不需要添加--experimental来支持RUN --mount=type=cache /user/.cache/pip pip install (为了节省大量的包索引带宽)。

buildah bud ( buildah build-using-dockerfile ) 有一个--volume / -v选项:
https://github.com/containers/buildah/blob/master/docs/buildah-bud.md

buildah可以在没有 docker 套接字的情况下以非 root 身份运行构建。

因为从网络上下载包的重现性更高?

无需在客户端添加“--experimental”,只需添加“DOCKER_BUILDKIT=1”即可。

是的,网络构建更具重现性,因为上下文都在 Dockerfile 中。 如果您必须从主机挂载上下文以使构建工作,这是一种糟糕的体验。

请注意,您还可以将映像挂载到构建中。

是的,网络构建更具重现性,因为上下文都在 Dockerfile 中。

在 Dockerfile 中肯定有RUN apt-get update可以确保一个人拥有构建映像所需的所有步骤。 但是,由于额外的上下文是从第三方下载的,因此它是不可重现的。 与挂载的唯一区别是所有外部上下文确实都在 Dockerfile 中定义。

如果您必须从主机挂载上下文以使构建工作,这是一种糟糕的体验。

我对 Docker 构建的糟糕体验是它永远无法重现,我们绝对可以从从主机安装缓存中受益,这可以加速某些用例。

我最终要做的是进行多阶段构建。 从网络获取上下文的图像,因此充当远程上下文的快照。 然后用一些任意版本标记它,日期可以正常工作。 例如:

RUN apt-get update

docker build -t aptupdate-20190417

在实际图像中:

FROM aptupdate-20190417
FROM somebaseimage

COPY --from=aptupdate-20190417 /var/apt /var/apt

与其他远程上下文重复,您或多或少有一些可重现的东西。

或者简而言之:依赖网络访问的 Dockerfile 可能无法重现。 挂载可能使其不可重现,但有助于使某些用例可重现。 但我认为 Dockerfile 应该具有实际构建映像所需的所有步骤,尽管根据我的经验,大多数人都编写自己的工具来检测构建映像。

我的意思是, RUN --mount=type=cache正是为此。
或者您甚至可以从注册表中的另一个映像挂载它,它将被获取。

您的apt命令可以(相对)通过固定您要获取的内容来重现。
但是如果你真的想控制所有的位,那你为什么要在你的构建中使用 apt 呢? 将其存储在构建主机上是不可重现的,并且很容易在主机之间中断。
将其保存在注册表中除了可能导致网络故障之外还不错……这当然是一个公平的批评。

buildah 和 redhat 的 fork 上的-v在这里被明确拒绝,因为它过于宽泛......并不是说它没有用,而是它很容易在主机之间中断,这与docker build的设计背道而驰.
同时,RH 添加它的原因(或者更准确地说,他们决定使用它的原因)是能够将 RHEL 凭据挂载到构建环境中。

是的,网络构建更具重现性,因为上下文都在 Dockerfile 中。 如果您必须从主机挂载上下文以使构建工作,这是一种糟糕的体验。

我强烈反对。 网络可能已关闭或受到威胁; 在这种情况下,本地缓存可以防止整个构建在互联网关闭时失败。

可以在 docker-compose.yml 中指定一次volumes: ; 但需要做DOCKER_BUILDKIT=1并在上游管理的 Dockerfiles 中添加RUN --mount=type=cache ? 为什么?

对于 CI 构建,我们正在谈论大量不必要的重新下载数十到数千个包(每天数十或数百次),这些包可能只是缓存在卷安装中(在以非 root 身份运行的构建中,没有能够在主机上使用自己的卷执行特权容器)。

包索引在许多情况下都得到了捐赠的慷慨支持。 将这笔钱浪费在带宽上以满足一些关于可重复性的错误想法,这种想法基于一种错误的信念,即远程资源是构建组件的可重现性更高的缓存,这是非常令人沮丧的。

请添加--volume以便我的 docker-compose.yml 工作。

请添加 --volume 以便我的 docker-compose.yml 工作。

让你的“docker-compose”正常工作是倒退的。
docker-compose 消费者这个项目,而不是相反。

docker-compose 与 docker 套接字交互。 docker-compose YAML 是一种存储容器选项的整合方式(可以转换为 k8s pod defs(podman 在一定程度上支持))。 我应该如何以可重现的方式指定DOCKER_BUILDKIT=1 ? 我可以在 docker-compose.yml 中以可重现的方式指定build_volumes:

当我——在我每天运行 n 次的 CI 构建脚本中——通过调用docker-compose build (例如使用 ansible)或packer (而不是 buildah 和 podman)来构建映像时,我有几个目标:

  • 节约资源/不浪费资源

    • 不要经常重新下载操作系统和每种语言的包。

    • 保存我组织的带宽资源包索引。

  • 确保可用性

    • 它应该/必须离线工作

    • 它应该依赖尽可能少的组件

  • 确保构建完整性

    • 能够使用相同的参数重新创建相同的图像

    • 隔离方差/提供可重现的构建

    • 我们不控制包索引等远程资源。

    • 我们不控制网络路径



      • DNSSEC 和基于 HTTPS 的 DNS 可能未正确实现



    • 我们可以被禁止和相当有限的速率

    • 我们应该使用签名校验和来验证签名资源



      • 授权访问和使用密钥签名在某处被委派


      • ENVironment 变量可用于容器命名空间中的所有进程


      • 构建时卷挂载是仅在构建时共享所需密钥的一种方法(不会将它们泄漏到映像缓存中)



  • 保持快速构建

    • 缓存和记忆频繁的操作。

    • 缓存确实增加了故障点、潜在的差异和不可重现的风险。



      • HTTP(S!) 代理缓存


      • 网络上的应用层缓存


      • 本地文件系统缓存



    • 实现没有外部依赖的哑的、可刷新的缓存



      • 本地文件系统缓存



如果我需要刷新缓存卷,我可以刷新缓存卷。

0.现状

RUN pip install app && rm -rf /root/.cache
  • 今天可能
  • O(n_builds):带宽使用
  • 无法离线工作:取决于网络
  • 较慢的重建

A. 副本

COPY . /app/src/app
COPY .cache/pip /app/.cache/pip
RUN pip install /app/src/app \
    && rm -rf /app/.cache/pip
  • 今天可能
  • ~O(1) 包索引带宽
  • O(n):每次构建时 (* ONBUILD )

    • 复制缓存

    • 取消归档包

    • 删除缓存

  • 离线工作
  • 较慢的重建

B. fork 并修改上游的每个 Dockerfile 以添加RUN --mount=type=cache并设置环境变量

# Fork by copying to modify every pip install line
RUN --mount=type=cache /app/.cache/pip pip install /app/src/pip
$ DOCKER_BUILDKIT=1 docker build . [...]
  • 今天可能
  • 这已经引入了不可重现性:有一个额外的 Dockerfile、extra-docker-compose.yml 参数在输出中引入了差异:命名的构建图像。
  • 文档:如何刷新--mount=type=cache缓存(?)
  • ~O(1) 包索引带宽
  • 离线工作
  • 快速重建

C. 指定在构建时安装的卷

C.1。 建立
$ buildah bud -v .cache/pip:/app/.cache.pip
  • 今天可能
  • 还引入了不可再现性
  • 文档:如何刷新缓存
  • ~O(1) 包索引带宽
  • 离线工作
  • 快速重建
C.2。 码头工人(这个问题要求什么)
C.2.1 码头工人 CLI
$ docker build -v .cache/pip:/app/.cache.pip
  • 今天不可能
  • 还引入了不可再现性
  • 文档:如何刷新缓存
  • ~O(1) 包索引带宽
  • 可以离线工作
  • 快速重建
C.2.2 码头工人撰写
services:
  app:
    image: imgname:latest
    build: .
    build_volumes:  # "build_volumes" ?
    - ./.cache/pip:/app/.cache/pip
$ docker-compose build
  • 今天不可能
  • 还引入了不可再现性
  • 文档:如何刷新缓存
  • 需要 docker-compose 架构修订
  • ~O(1) 包索引带宽
  • 可以离线工作
  • 快速重建

...

  • 复制 || REMOTE_FETCH || 读()

    • 其中哪一个是最可重复的?

:point_up: 只是一个提醒。 您可以通过检查其校验和来固定下载的文件。 一些包管理器,例如 pip,也支持这一点。

@westurner感谢您的详细解释。

我认为以下内容与您的案例 B 类似,但您可以清除缓存,最终会像您的案例 C2 一样(我认为您所要求的):

_docker-compose.yml:_

services:
  my-cache:
    build: ./my-cache
    image: local/my-cache

  my-image:
    build: ./my-image

_my-cache/Dockerfile:_

FROM python

RUN pip install app

_my-image/Dockerfile:_

FROM my-repo/my-image

RUN --mount=target=/export,type=bind,from=local/my-cache

RUN pip install /app/src/app

(https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md#run---mounttypecache)

您可以使用以下命令构建缓存映像:

docker-compose build my-cache

命令RUN --mount=target=/export,type=bind,from=local/my-cache应该绑定到图像。 如果要刷新缓存,可以删除并重建缓存图像。

如果这仍然使用RUN --mount...中的缓存,您可以使用带有版本的.env文件,将版本包含在image: local/my-cache:$MY_VERSIONfrom=local/my-cache:$MY_VERSION中(应该是包含在构建 arg 中)。

如果您不希望my-cache服务与您的主要服务在同一个文件中,您可以将它包含在另一个docker-compose文件中。

您仍然需要使用DOCKER_BUILDKIT=1 (就像在您的 B 案例中一样,但我认为在未来的版本中这将不是必需的)并且它仍然无法重现(但您的 C2 案例也不是)。

如果它不可重现,你会看到什么惩罚? 如果您将缓存映像local/my-cache放在docker hub (具有不同的 repo 名称)或私有注册表中并为每个构建使用版本(这将创建不同的缓存),相同的版本始终相同缓存,它不会使它可重现吗? 您甚至不需要在docker-compose文件中包含该服务并调用构建命令。 (Docker Hub应该可以从网络上访问,但我认为你的其他镜像也是一样的,下载一次后,应该不再需要它了,除非你生成一个带有新缓存的新版本)

免责声明:我没有测试过上面的代码。

@Yajo pip 中的校验和支持最初是在 'peep' 中实现的,然后合并到 pip 中。 您可以在 pip 需求文件条目中添加已知的良好哈希作为 URL 片段。 (今年为 PyPA 项目的安全改进提供了资金;计划在今年晚些时候在 PyPI 中支持 TUF(更新框架;就像 Docker Notary)。)在 docker 镜像中正确引导 pip 和 PyPI(带有密钥和信任)今年晚些时候可能会成为一个话题。
(编辑;有点过时,但对于有关方面) https://discuss.python.org/t/pypi-security-work-multifactor-auth-progress-help-needed/1042/

@lucasbasquerotto感谢您的帮助。 这比在构建时指定--volume要复杂得多。 即,它似乎需要:

  • docker build shell 环境中指定DOCKER_BUILDKIT=1
  • 使用(编辑) RUN --mount=type=cache和 args 修改任何/每个上游 Dockerfile RUN 指令
  • 读/写访问另一个图像? 可变性! 或者说缓存被可能过时的版本冻结了?

如果我可以从主机复制文件,或指定未存储在其他地方的构建时参数,我看不出在构建时安装卷的可重现性如何?

复制 || REMOTE_FETCH || 读()

  • 其中哪一个是最可重复的?

@westurner

在 docker build shell 环境中指定 DOCKER_BUILDKIT=1

如果您使用docker-compose ,正如我在您的其他帖子中看到的那样,并且如果您从容器中运行它,例如:

$ sudo curl -L --fail https://github.com/docker/compose/releases/download/1.24.0/run.sh -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose

然后您可以在/usr/local/bin/docker-compose中编辑下载的文件以使用该环境变量。 更改自:

exec docker run --rm $DOCKER_RUN_OPTIONS $DOCKER_ADDR $COMPOSE_OPTIONS $VOLUMES -w "$(pwd)" $IMAGE "$@"

DOCKER_BUILDKIT=1
exec docker run --rm $DOCKER_RUN_OPTIONS $DOCKER_ADDR $COMPOSE_OPTIONS $VOLUMES -w "$(pwd)" --env DOCKER_BUILDKIT=$DOCKER_BUILDKIT $IMAGE "$@"

这是一个非常简单的更改,并且对运行该命令的人来说是透明的。

_(如果不作为容器运行,则上述不适用)_

使用 RUN --cache 和 args 修改任何/每个上游 Dockerfile RUN 指令

在我公开的情况下,它将是RUN --mount=type=bind... ,但无论如何,必须更改Dockerfile也是糟糕的 IMO。 -v选项确实会更好更透明

读/写访问另一个图像? 可变性! 或者说缓存被可能过时的版本冻结了?

当您绑定图像时,它可能会创建一个容器(或任何名称,具有复制的文件系统),并且在构建时在那里完成的更改不应更改原始图像(这没有意义)。 因此,如果您在构建中使用名为my-repo/my-cache:my-version的缓存映像进行构建,则在下一个构建中它将完全相同(不变性)。 如果您想使用更新的缓存,您可以使用新版本创建新图像并使用它,例如my-repo/my-cache:my-new-version

其中哪一个是最可重复的?

我认为即使你在另一台机器上运行它,它也可以重现。 从这个意义上说,如果您将映像推送到(安全且可靠的)docker 注册表,并且从不更改该映像,我会认为它是可重现的(如果您担心互联网连接,您可以使用私有注册表并在VPN 或类似的东西(我自己从未使用过私人注册表))。

如果 COPY 命令正在复制您的机器缓存,我认为它不可重现,因为如果您在另一台机器上运行pip install (或apt-get或其他任何东西),您能否保证那缓存的内容会一样吗? 也许这可能是您担心的问题。 也许不吧。

另一方面,如果您在“拥有”的某个可靠位置(例如 S3 存储桶)拥有自己的文件,请将这些文件下载到您的机器中并使用 COPY 命令复制这些文件,然后您可以从另一个具有相同结果的机器(假设文件没有更改,并且另一台机器与前一台相同)。 所以我认为这是可重现的。 这取决于这些文件的来源以及您对它们的控制程度。

说实话,我不认为任何事情在所有情况下都是 100% 可重现的(毕竟,硬件可能会发生故障),但越可靠越好。 当我提到某些过程是可重现的时,我主要是指它的内容和结果是相同的,这包括从网络下载的东西,假设内容不随时间变化(我不考虑网络的可能性在这种情况下失败)。

有某种 Docker 网络错误导致容器内的go mod download也不可靠(至少对于我们大小的应用程序而言),所以每次运行它以重新下载我所有的GOPATH/pkg/mod是不仅浪费,而且损坏。 🤷‍♀

如果我可以使用--volume ,我可以避免大量不必要的文件复制!

@kevincantu RUN --mount=type=cache 应该涵盖您的用例

这需要从 docker build 中至少成功下载一次模块,在这种特殊情况下,我还没有见过..

@westurner 的https://github.com/moby/moby/issues/14080#issuecomment -484314314是一个很好的概述,但我无法让buildkit工作:

$ sudo docker -v
Docker version 19.03.1, build 74b1e89

$ sudo DOCKER_BUILDKIT=1 docker build .
Ä+Ü Building 0.1s (2/2) FINISHED                                                                                                                
 => ÄinternalÜ load build definition from Dockerfile                                                                                       0.0s
 => => transferring dockerfile: 407B                                                                                                       0.0s
 => ÄinternalÜ load .dockerignore                                                                                                          0.0s
 => => transferring context: 2B                                                                                                            0.0s
failed to create LLB definition: Dockerfile parse error line 8: Unknown flag: mount

我的Dockerfile确实以# syntax=docker/dockerfile:experimental开头。

我实际上想通过docker-compose使用它。 在Dockerfile $ 中尝试ENV DOCKER_BUILDKIT 1 $ 并通过ARG DOCKER_BUILDKITdocker-compose.yml传递它,但都是一样的:

$ sudo docker-compose up --build
Building web
ERROR: Dockerfile parse error line 10: Unknown flag: mount

@lucasbasquerotto您在https://github.com/moby/moby/issues/14080#issuecomment -484639378 中提出的建议如何转化为已安装的 docker-compose 版本?

最后,我什至不确定这是否会涵盖我的用例,也许你们中的一些人可以告诉我是否应该继续这样做。 我想为本地开发使用构建时缓存,该缓存在构建之间存在,因此在更新依赖项时,只需下载新的依赖项。 所以我会将RUN --mount=type=cache,target=/deps添加到Dockerfile并将依赖项管理器的缓存设置为/deps

对于 docker compose,请参见https://github.com/docker/compose/pull/6865 ,它将在即将发布的 compose 候选版本中

我还有另一个用例...我想在配置了 binfmt 的 x86_64 主机上为 arm 构建容器。 这要求我在/usr/bin中具有特定于体系结构的静态 qemu cpu 模拟器。

我目前的解决方案是将qemu-arm-static作为文件添加到容器中,例如:

FROM arm32v7/alpine:3.10
COPY qemu-arm-static /usr/bin/qemu-arm-static
RUN apk update && apk upgrade
RUN apk add alpine-sdk cmake
...

更简单的解决方案是仅在容器内需要时才安装我的文件,例如:
docker build -v /usr/bin/qemu-arm-static:/usr/bin/qemu-arm-static -t test:arm32v7 .
这对 docker run 非常有用,但我想念这个用于构建容器的功能。

是否有另一种解决方案如何在 x86_64 主机上构建 arm 容器,或者至少在这种情况下我们可以在构建时允许卷?

@jneuhauser最新内核允许静态加载这些二进制文件,因此无需每次都配置它们。 例如,您可以通过在启动后以特权模式运行linuxkit/binfmt映像来实现此目的。

最新的内核允许静态加载这些二进制文件,因此无需每次都配置它们。

@alehaa不过,您是否还需要容器中的静态 qemu 模拟器二进制文件?

@cybe如果使用了F -flag(这是linuxkit/binfmt包所做的),则不再需要此功能。 您可以在此处找到有关此的更多信息。

有人可以提供尝试 buildkit 的工作设置吗? 我无法让它在 Ubuntu 上运行。 我的设置如下:

cat /etc/docker/daemon.json

{
  "experimental": true
}

Dockerfile

# syntax=docker/dockerfile:experimental

FROM ruby:2.6.3

RUN --mount=type=cache,target=/bundle/vendor

sudo docker -v

Docker 版本 19.03.1,构建 74b1e89

DOCKER_BUILDKIT=1 sudo docker build .

来自守护进程的错误响应:Dockerfile parse error line 12: Unknown flag: mount

sudo不携带环境变量,除非你用sudo -E告诉它或在 sudo 中声明变量。

写了一些关于这个特性的文字并创建了一些最小的例子来展示如何缓存

编辑:见下文

@cpuguy83谢谢!

@thisismydesign很抱歉破坏了您的兴奋,但您不能 --cache node_modules ,它不会出现在最终图像中,因此您的应用程序已损坏。

@glensc该死的你是对的..有没有办法让构建时缓存成为最终图像的一部分?

老实说,我认为这将被视为宣传为的功能

允许构建容器为编译器和包管理器缓存目录。

你应该能够映射 ~/.npm 来代替...... https://docs.npmjs.com/files/folders.html#cache

@thisismydesign

但是,您可以使用另一个图像作为缓存,方法是在您的 Dockerfile 中构建它或存储在某个地方的注册表中的文字图像并使用COPY --from

FROM example/my_node_modules:latest AS node_modules

FROM nodejs AS build
COPY --from=/node_modules node_modules 
...

这只是一个示例,您可以将其用于许多不同的事情。

呃,我讨厌提出这个问题并参与其中(还有朋友们)

但我们有一个用例。


有没有一个我可以参与的好地方,或者我可以加入一个电话或列表来获取摘要?

此外,如果我们需要有人为此提供一些资源,我有 1 个 kris nova 和一个小团队,我可能会说服我看看这个。

TLDR我可以编码吗? 有没有人可以和我谈谈这个?

_TLDR_我可以编码吗? 有没有人可以和我谈谈这个?

我不能代表 Docker,但我的印象是他们不愿意为构建添加卷安装(他们可能应该关闭这个问题)

buildkit 现在涵盖了 buildtime -v 的许多用例。 它至少为我解决了它。

然后我会检查 buildkit - 如果有人感兴趣,我还有一些 hacky bash 可以完成工作。

谢谢@unilynx

+1 对@unilynx关闭此问题,buildkit 也为我解决了构建时间量问题。

我敢打赌,如果有人删除了一些链接和一个例子,我们可以说服我们的朋友按下闪亮的关闭按钮。


(我也会从中受益)

缓存的用例对我和其他许多人来说都没有解决,因为最终图像中不存在 buildkit 的构建时间量。

因此,我能够从build时间使用的临时卷中提取所有构建工件,并使用我上面提到的这个 bash 再次使用以前的缓存重建图像。

我能够在其自身之上重建我的图像,这样覆盖文件系统只抓取了一个小增量。

我什至能够在构建时将卷重新用于其他图像。


其他人不能做到这一点吗?

(缓存)挂载在“实验”前端; 在https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md中描述(即将参加会议,但我可以链接更多扩展示例)

感谢@thaJeztah LMK,如果我能以任何方式在这里提供帮助:)

https://github.com/moby/moby/issues/14080#issuecomment -547662701

@thisismydesign很抱歉破坏了您的兴奋,但您不能 --cache node_modules ,它不会出现在最终图像中,因此您的应用程序已损坏。

@thaJeztah我不相信上述问题已解决。 很想看一些可以缓存的示例,例如在构建期间缓存npm install ,这也将允许生成的图像使用缓存的安装。

@kris-nova 我没有解决这个问题,但我又不想使用 bash 脚本。 也许我们需要一个新问题,但这是一个非常常见的用例,AFAIK 尚未解决。

@thaJeztah以下是一些使用缓存挂载的示例,展示了最终映像如何不包含挂载,并且它没有涵盖许多构建时缓存的用例:

对于 npm:不会使用 npm 缓存目录的缓存挂载(请参阅 https://docs.npmjs.com/cli-commands/cache.html,通常是~/.npm )?

@ankon这可以工作,谢谢,我会试一试。 我不确定的另一个用例是 Bundler 和 Ruby。

所以我认为(尚未测试)对于 Bundler,您至少可以通过使用$BUNDLE_PATH的构建卷然后在构建期间摆脱网络依赖

bundle install
bundle package
bundle install --standalone --local

这基本上意味着您有一个缓存的捆绑安装目录,从那里您将 gem 打包到./vendor/cache并重新安装到./bundle 。 但这并没有节省安装和构建 gems 的时间,它实际上可能会使构建步骤更长。

如果要将缓存的数据保存到图像中,则将其从缓存中复制到图像中。

谢谢,但是,它仍然是一种解决方法,因为

  • 你必须做一个额外的副本
  • 我假设您必须在构建和运行环境之间有不同的目录(您不能使用在构建过程中安装卷的目录,对吗?)所以它需要额外的设置

我不知道简单地使用本机选项将相同的卷安装到最终图像中需要付出多少努力,但我很确定它会使使用变得更容易。 这些只是脚本语言中的 2 个示例,其中使用此缓存的方式对我来说并不明显。 我可以肯定地想象这也会出现在不同的环境中。

@thisismydesign似乎您想要的是能够在构建和运行之间共享缓存?

buildkit 是一个仅限 linux 的解决方案,我们在 windows 上做什么?

@thisismydesign我不确定您为什么希望(缓存)挂载保留在最终图像中。 我没想到这一点,我不想仅仅因为使用下载缓存挂载而在我的图像中有 ~1gb。

buildkit 是一个仅限 linux 的解决方案,我们在 windows 上做什么?

您可以在 Windows 上使用 buildkit。

https://docs.docker.com/develop/develop-images/build_enhancements/

您可能会发现通过 Docker for Windows UI 设置守护程序设置比在执行前设置环境变量更容易。

@nigelgbanks在您的链接顶部:

Only supported for building Linux containers

哦,对不起,我只是假设您正在 Windows 上构建 Linux 容器。

@thisismydesign似乎您想要的是能够在构建和运行之间共享缓存?

这将解决我围绕缓存的用例,是的。

使这更容易可以节省数百万次在 CI 中重新下载包的次数
每年建造。

是否有任何 CI 服务支持实验性buildkit 功能?

2020 年 6 月 13 日星期六下午 2:08 Csaba Apagyi [email protected]写道:

@thisismydesign https://github.com/thisismydesign看起来像什么
您想要的是能够在构建和运行之间共享缓存吗?

这将解决我围绕缓存的用例,是的。


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看
https://github.com/moby/moby/issues/14080#issuecomment-643657987 ,或
退订
https://github.com/notifications/unsubscribe-auth/AAAMNS6IEQDCO5F3LNHJK5TRWO6AJANCNFSM4BJB2OOA
.

是否有任何 CI 服务支持实验性buildkit 功能?

他们必须明确支持吗? 我将 gitlab-ci 与 buildkit 一起使用,它可以正常工作。 毕竟,这只是调用“docker build”的另一种方式。

当然,除非您将自己的跑步者带到 gitlab,否则在构建期间获得缓存命中的几率无论如何都很低。

从多阶段构建的命名阶段复制是另一种解决方案

FROM golang:1.7.3 AS builder
COPY --from=builder

但是容器镜像局部性仍然是 CI 作业调度的一个主要未解决的问题

跑步者需要更有粘性并在公共文件系统中共享(中间)图像,以最大限度地减少对(长期资金不足的)软件包回购的不必要请求。

我刚刚尝试buildkit ,但它只是略微改善了我的工作流程,这将 100% 得到“真实”卷或绑定到主机的帮助。

我正在使用docker build交叉编译旧的glibc版本,这些版本应该是新构建容器的一部分,提供这些glibc来构建和链接。

现在重复的glibc源下载通过绑定挂载(来自buildkit )解决,存档可以只读,没问题。 但是在构建失败后我无法访问构建目录进行分析,因为容器会因错误而爆炸。 (如果我重新启动它以访问它,它会重新启动构建,所以这无济于事)。

另外,我不明白为什么我应该像从旧容器中构建一个新容器一样跳过箍只是为了摆脱我的构建目录,如果构建目录首先是一个挂载,它本来是太简单。 (只需在构建后执行make install ,我就有一个干净的容器,没有构建目录,也没有下载的源代码)。

所以我仍然相信这是一个非常有效的功能请求,会让我们的生活更轻松。 仅仅因为一个特性可能被滥用并且如果使用它可能会破坏其他功能,并不意味着应该不惜一切代价避免实现它。 只需将其视为更强大工具的额外用途。

但是在构建失败后我无法访问构建目录进行分析

听起来像是对 buildkit 的功能请求。 这绝对是一个已知的缺失部分。

今天可以通过获取“构建目录”的目标来做到这一点。 您只需在运行失败后运行它,所有内容仍应被缓存,只需要最后一步来获取数据。
不过,请理解这是一种解决方法。

另外,我不明白为什么我应该像从旧容器中构建一个新容器一样跳过箍只是为了摆脱我的构建目录

你能在这里解释更多你想要/期待什么吗?

你能在这里解释更多你想要/期待什么吗?

在这种情况下,它只是想用 1 块石头杀死 2 只鸟:

  • 有一种从主机访问中间结果的简单方法(这里是“构建目录分析”)
  • 确保这个存储空间没有污染新建的镜像

由于这一点,以及构建容器(以及“容器构建”)需要使构建尽可能轻松的所有其他情况,只需提供-v功能就可以更优雅地解决,我有一个很难理解提供此功能的阻力。 除了buildkit显然提供的“缓存感知”功能之外,我只能将其视为实现此功能的一种复杂且繁琐的方式,而且只是部分实现。 (并且在许多以缓存为主要目标的情况下,它也可以通过-v来解决,代价是只要它运行就必须将已挂载的卷锁定到特定容器,但使用buildkit #$ 的缓存

你能在这里解释更多你想要/期待什么吗?

我正在使用多阶段构建过程,其中构建环境本身是容器化的,最终结果是一个仅包含应用程序和运行时环境(没有构建工具)的图像。

我想要的是临时 Docker 构建容器在构建成功和构建失败的情况下向主机系统输出单元测试和代码覆盖率结果文件的某种方式,而无需将它们传递到构建输出映像中用于提取(因为如果单元测试在前面的步骤中没有通过,整个构建过程就会短路,所以在这种情况下不会有输出图像,这就是我们最需要单元测试结果的时候) . 我想如果主机卷可以挂载到 Docker 构建过程,那么内部测试命令可以将它们的输出定向到挂载的文件夹。

@mcattle
确实也与我需要的(功能之一)非常相似。
自从几天前搬到buildah后,我得到了我需要的每一个功能,甚至更多。 如果不能灵活地进入退出的容器并链接到主机,调试我的构建容器是完全不可能的。 现在我是一个快乐的露营者。 (我很抱歉用“竞争对手”来破坏派对,如果冒犯,我很乐意删除这条评论,但对于这个线程中提出的用例来说,这是一个非常有效的解决方案,我想我应该提到它) .

说另一种工具更适合您的需求并没有冒犯。

如果有什么对你有用,那就太好了。

在这种情况下,Docker 中的 v1 构建器和 buildkit 构建器的缺点都得到了很好的理解,并且正在研究如何解决这些问题,最好不要求助于客户端的绑定挂载。
GitHub通知@github.com 写道:
“@mcattle
确实也与我需要的(功能之一)非常相似。
自从几天前搬到 buildah 后,我得到了我需要的每一个功能,甚至更多。 如果不能灵活地进入退出的容器并链接到主机,调试我的构建容器是完全不可能的。 现在我是一个快乐的露营者。 (我很抱歉用“竞争对手”来破坏派对,如果冒犯,我很乐意删除这条评论,但对于这个线程中提出的用例来说,这是一个非常有效的解决方案,我认为我应该提到它) 。”


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看,或退订。

无需求助于客户端的绑定挂载。

在这里,我解释了为什么构建时间 -v 选项不诉诸或牺牲可重复性,而不是依赖于构建时的网络资源。

https://github.com/moby/moby/issues/14080#issuecomment -484314314:

复制 || REMOTE_FETCH || 读()

  • 其中哪一个是最可重复的?

我也将使用 buildah 来构建时间-v (和 cgroupsv2)。

@mcattle我有同样的要求。 我用 label解决了它。

我也将使用 buildah 来构建时间-v (和 cgroupsv2)。

由于“-v”支持,我正在认真考虑在我们的构建服务器上从 Ubuntu(只有 docker)切换到 Fedora(已经用 podman/buildah 替换了 docker)。

顺便提一句。 Podman 还支持无根模式,到目前为止,它似乎与 Docker 完全兼容(除了 --user/USER 影响和图像缓存方面的差异,这些差异来自使用无根模式而不是像 Docker 守护程序那样以 root 身份运行)。

PS。 虽然无根操作需要 cgroups v2,但对它的支持更多的是关于容器运行时,而不是 docker。 如果您使用 CRun 而不是 RunC(就像 Fedora 一样),您将获得 cgroups v2 支持。 RunC 在 Git 中确实有一些 v2 和 rootless 支持,但是几个月前我在 Fedora (31) 上测试它时遇到了一些问题。

编辑:Ubuntu 在 Groovy 中有 podman/buildah/etc,只是在最新的 20.04 LTS 中没有,我认为是从 Debian 不稳定导入的。 它还没有被反向移植到 LTS,至少现在还没有。 而我认为它自 2018 年以来一直在 Fedora 中。

@eero-t 也许您可以描述您的用例,以及 BuildKit 当前提供的选项中缺少的内容,而这些选项并未针对这些情况进行处理。

此页面是否有帮助?
0 / 5 - 0 等级