Moby: 添加对使用 -i/--ignore 指定 .dockerignore 文件的支持

创建于 2015-04-30  ·  140评论  ·  资料来源: moby/moby

正如几个人在 #9707 中提到的( @thaJeztah和 @duglin),能够使用 -i/--ignore 和命名的 dockerfile 来指定 .dockerignore 文件会很棒。 由于构建上下文变得太大,通常很难使用命名的 dockerfile。

arebuilder exbeginner kinfeature platforwindows

最有用的评论

我没有为此工作。

考虑-f ,这似乎是一个自然的选择,因为 -f 使得有效使用 .dockerignore 变得更加困难。 如果没有 -i,我们的 repo 就不可能使用 -f,因为我们的构建上下文是 1GB+。 我们有非常经典的设置:具有许多共享代码的服务的单个 repo。 我们希望能够在没有自定义脚本或缓慢构建的情况下构建所有这些服务。

所有140条评论

dibs 或对不起@tristanz你已经在努力了吗?

需要明确的是,我并没有说我想要它 - 只是它可以得到支持。
在实施之前,您可能想先看看是否有团队的支持。

@runco ​​m ^^^^

收到!

我没有为此工作。

考虑-f ,这似乎是一个自然的选择,因为 -f 使得有效使用 .dockerignore 变得更加困难。 如果没有 -i,我们的 repo 就不可能使用 -f,因为我们的构建上下文是 1GB+。 我们有非常经典的设置:具有许多共享代码的服务的单个 repo。 我们希望能够在没有自定义脚本或缓慢构建的情况下构建所有这些服务。

不是维护者(为此),我会为此 +1,以便不同的 Dockerfile 可以排除构建上下文的不同部分。

我不确定是否需要单字符标志( -i ),也许是--ignore-file (匹配,例如--env-file )。

@tristanz也许您可以描述此功能的一些用例,它可以帮助维护人员做出有根据的决定,无论这是否是想要的东西

编辑:
我们的评论刚刚“交叉”,我看到您刚刚在您的用例中添加了一些描述

是的,我相信我们的用例正是命名的 dockerfile 线程中描述的用例:一个包含许多共享库的服务的单个 repo。 所以这只是试图使相同的用例适用于实际设置。 像这样的单个 repos 往往很大(我们喜欢它有很多原因!),所以没有 --ignore-file 我们不能使用 -f 并且被迫诉诸预构建脚本。

@tristanz你能提供更多关于这些大型回购的细节吗? 特别是,当我考虑具有多个子项目的大型存储库时,我认为将其视为每个项目都有自己的子目录和自己的 Dockerfile ,但它们都共享一个公共目录,可能是每个项目的兄弟。 例如:

/common
/project1
/project2

在这些情况下,我想知道是否支持符号链接不会更容易。 意思是, /project1/common/common的符号链接。

另外,需要明确的是,我不赞成或反对 --ignore 标志 - 仍在尝试理解用例。

@duglin这正是我的设置。 实际上,我_much_ 更喜欢符号链接支持来解决这个问题。 感觉不太特定于 docker,允许保持我的 dockerfiles 不变(子文件夹构建上下文),并且我可以避免编写大量 dockerignore 文件。 我只是觉得命名 dockerfiles 是推荐的替代方案。 到目前为止,我认为符号链接是更好的选择。

现在 Windows 是否支持符号链接? (想知道)

对于我个人的用例,一些容器是使用卷创建的,以在开发过程中挂载源代码。 在启动开发容器时能够排除这些文件(大量文件,而不是本身的大小)将节省大量时间。 (而且,是的,有一些解决方法)

我想主要问题是对于具有共享代码的多个容器 git repos 是否真的没有解决方案。 这似乎是一个非常常见的用例,但据我所知,任何关于符号链接或相对路径的讨论都没有找到吸引力。

这是我正在考虑的文件夹结构:

/docker-compose.yml
/container1
   - Dockerfile
/container2
   - Dockerfile
/shared

真的没有docker方式吗? 到目前为止,我发现的最好的方法是将 shared 复制到多个地方。

是否值得为此功能提出拉取请求?

是否值得为此功能提出拉取请求?

还没有决定,但你可以试试。 有机会被拒绝:)

有时讨论公关有助于做出决定,所以..取决于你,我猜:)

另一种解决方案是查找存储 Dockerfile 的 .dockerignore 文件,因为构建目录不一定是 Dockerfile 所在的目录,但我也更喜欢 -i。

另一种解决方案是查找存储 Dockerfile 的 .dockerignore 文件

不幸的是,如果多个 Dockerfile 在同一个目录中(例如Dockerfile.devDockerfile.prod ),这将不起作用

正确的。 那么用 Dockerfile 命令来描述对应的 .dockerignore 怎么样?

我认为建议的解决方案( --ignore-file选项)是最好的方法,也是最灵活的。 现在唯一需要做的就是确定这是否足以实现。

即使使用 dockerignore,我也不喜欢命名 dockerfile 的两点。

  1. Dockerignore 无处不在。
  2. 许多容器没有共享依赖项,但我的存储库的用户不清楚构建上下文应该是什么。 如果在任何地方都使用根上下文会很好,但是我们的存储库有公共 Dockefile 的分支,它们只假设本地上下文。

取消引用符号链接似乎更加优雅。 我总是可以看到每个文件夹中的所有依赖项,比如单个 Dockerfile 存储库。 除非设置了环境变量或标志,否则可以处理不允许符号链接逃逸到本地文件夹外部的安全性。

我收回我的第二点。 更好的约定是将 Dockerfiles 放在构建上下文的深处。 所以 Dockerfile.web 而不是 web/Dockerfile。 这将使上下文足够清晰。

就整个问题而言,构建上下文是整个文件夹,而不仅仅是明确添加的文件和文件夹(加上 Dockerfile/.dockerignore),是否有原因? 这将使多个 .dockerignore 大多是不必要的。

取消引用符号链接也看起来像一个非首发,因为已经有一个定义的行为——创建符号链接而不是取消引用它。

我制作了一个 Web 项目并拥有数十亿个文件。 为每个添加 ADD 会创建大量的中间容器,我需要一个脚本来为我构建我的 Dockerfile。

@ralle我认为不会有任何改变。 您只需像平常一样添加一个文件夹。 我只是建议避免焦油化和上传你从未添加的东西。

+1 至,按优先顺序:

1)构建上下文不应发送所有文件,如上面@tristanz所述。 为了保持向后兼容性,CLI 标志可以是--full-context ,默认为 true。
2)构建期间遵循的符号链接。
3) 自定义 .dockerignore,每期使用-i

我认为@pikeas list 中的 1) 是迄今为止最优雅的,但由于父图像可能具有 ONBUILD 指令,因此目前并不容易实现。

@tristanz web/DockerfileDockerfile.web之间的主要区别在于,在第一个上,您无法在该路径后面添加文件。

Dockerfile非常适合直接构建,但它缺乏对重要部署选项的支持,例如与环境相关的差异......

@fernandoneto请检查这是否适合您:

DOCKERPATH=/path/to/docker/build/folder
DOCKERFILE=Dockerfile.production
DOCKERIGNORE=.dockerignore.production
tar -cvzf - --exclude-from="$DOCKERPATH/$DOCKERIGNORE" $DOCKERPATH | docker build -f $DOCKERFILE -

_用户投票_

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

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

@alenca
@cusspvz
@fernandoneto

虽然我不反对通过选项指定.dockerignore文件,但我发现自己需要以下内容:

  • 能够指定多个.dockerignore (例如全局、上下文、 Dockerfile相邻)。
  • 无论如何,在这些地方看起来的默认行为。

我想声明这一点以及忽略内部的改进。

谢谢@mishak87

我将在此处 ping @tiborvass以检查这是否会与构建器中即将发生的更改发生冲突,但请随时在 IRC #docker-dev 上询问他(他在 IRC 上是“tibor”)

@mishak87我刚刚与@tiborvass聊天,对于即将到来的构建器更改,这应该不是问题。 请注意,此功能尚未做出“最终”决定,因此我们可以在您的 PR 的“设计审查”期间讨论和决定。

一样东西; 我会选择不使用短标志( -i )而只使用长标志( $ --ignore--ignore-file )。 我们尝试为经常使用的选项保留短标志(以后我们总是可以添加一个短版本)。

提前感谢您的贡献!!

@thaJeztah感谢您提供的信息,我将在下周进行处理。

惊人的! 提前感谢@mishak87!

这很有意义。 谷歌把我带到这里是因为我假设如果你可以指定一个命名的 Dockerfile,你就可以指定一个 .dockerignore 文件。

例如,如果您使用来自 Dockerfile.build 的胖映像进行构建,然后针对来自 Dockerfile 的瘦映像进行部署,那么您也希望拥有一个可能会忽略所有内容的 .dockerignore.build 是有道理的除了构建步骤中的二进制工件。

考虑到我的 repos atm 的大小,只有一点点烦恼,但谢谢@mishak87

稍后注意:因为这个评论已经在这里有一段时间了,我觉得我应该更新一下,即使这个问题是合法的,它也是一个 _aesthetic_,'dev UX' 类型的问题。

如果有人以 StackOverflow 的心情偶然发现我的评论,因为这实际上妨碍了单独构建和运行 dockerfile/dockerignore 对,请不要忘记您可以将它们放在不同的目录中。 即,在您的构建脚本中,在针对您的“构建”Dockerfile/ignore 构建并提取构建工件之后,将工件和“运行”dockerfile/ignore 移动到单独的顶级(可能是 gitignored)binary_artifacts 目录中。

+1

+1

+1

对此有何更新?

@thaJeztah我觉得我的公关卡住了。 我应该重写它以使其适用于最新更改吗?
我可以在九月底之前腾出时间。

+1

+1

让我们假设1) 上面默认情况下不发送整个上下文,那么上下文不能从 ADD 和 COPY 语句中的内容派生吗? 不需要 .dockerignore。

或者(保持兼容,即:默认发送整个上下文),因为 dockerignore 似乎特定于 Dockerfile,我们可以指定 dockerignore 在 Dockerfile 本身中使用。

顺便说一句,我遇到了一个带有两个 Dockerfile 的 .dockerignore 的问题(一个用于构建我的应用程序,另一个用于创建生产映像)。 我可能必须创建一个子目录才能从第二个 Dockerfile 构建。 这是我能想到的最简单的解决方案,无需为每个 Dockerfile 指定不同的 dockerignore。

@gittycat我喜欢你的方法,也许两者可以结合起来? ADD/COPY 指定要添加到上下文中的文件,.dockerignore 中要忽略的内容,似乎它们的角色略有不同。 这具有提高现有 docker 构建的性能和安全性的额外好处。

这有什么吸引力吗?

当您通过 docker 构建多个图像时,拥有一个 .dockerignore 很烦人,但一旦您使用 docker-compose,这确实是个问题。 然后你就不能再玩弄符号链接了。

此外,docker-compose 有一个正是这个 bug,直到 docker 支持这个特性才能实现它——https: //github.com/docker/compose/issues/2098

我同意其他同事的观点,如果 docker 从 Dockerfile 中生成 COPY 和 ADD 命令的上下文,而忽略所有不存在的文件,那么 .dockerignore 将是真正可选的。

--ignore选项也应该采用多个忽略文件

缺少此功能会阻止我们在执行 CI 时并行运行 docker 构建。

我们的测试脚本开始是这样的:

cp foo/dockerignore .dockerignore
docker build -f foo/Dockerfile .
cp bar/dockerignore .dockerignore
docker build -f bar/Dockerfile .
...

这些构建可以并行进行,以实现巨大的加速。 慢 CI 的用处要小得多。 :(

一个常见的 .dockerignore 会产生大约 10GB 的上下文。

此功能已暂停,等待正在研究/处理的其他更改; 其中之一是在发送构建上下文时使构建器“更聪明”; 见https://github.com/docker/docker/issues/31829

关于何时进行这项工作的任何更新? 在单体仓库中工作时,这将解决我的很多问题。

我今天也遇到了这个问题。 我已经花时间阅读了所有这些讨论和大部分相关的 PR。

我的观点是总体上有很多改进构建的激进方法,但是今天我们有一个非常好的和简单的方法来声明一些文件被忽略。 只有一个明显的问题,虽然我们可以随意命名 Dockerfile(因此允许从同一目录构建不同的 docker),但我们不能随意命名 .dockerignore,因此我们大多数人最终会发送大量的东西到上下文,我们不需要因此加载网络+构建时间不必要。

我不明白为什么一个简单的 PR 只添加一个选项(应该用 -f 完成),--ignore-file (即使它是一个)与未来添加其他方法来更改上下文的工作冲突(我假设由于向后兼容性 .dockerignore 将始终是一个选项,因此人们总是希望选择重命名它)。

@thaJeztah你能重新打开#18754 吗? 我看到您写道,由于 #31829 和其他更改,此功能被搁置。 但是,如果您不打算使用.dockerignore从构建上下文中删除忽略文件,那么我看不到此功能与其他更改有何冲突。 令人沮丧的是,我们仅限于.dockerignore文件名并且需要弄乱脚本并且使用 docker-compose 只是浪费时间和资源而没有选择为多个大型服务使用不同的.dockerignore文件共享构建上下文。 #18754 只有 32 行代码,在这两年里它已经可以帮助很多人。
我同意@tzickel - 这是非常小且非常有效的更改,不需要艰苦的工作和大的建议。

@thaJeztah您能否指出哪个文件处理clitar的创建?

很抱歉破坏了聚会,但我遇到了类似的问题,我怀疑由于存储库设计和布局错误而需要它。 您需要跟踪每个新文件添加并更改多个 dockerignore,因此还要求您在 docker ignores 之间进行包含......然后是模板......天知道是什么。

需要多个 dockerignores 表明手头有一个更大的问题。 为什么一个还不够? 因为架构耦合不当。

我提出了一个折衷方案,即 docker 客户端首先尝试加载<dockerfile-name>.dockerignore ,如果找不到,则回退到.dockerignore 。 所以docker build -f Dockerfile.foo .会首先尝试加载Dockerfile.foo.dockerignore

这种方法的优点是它不鼓励创建仅在将某些特定选项传递给docker build时才起作用的 Dockerfile。 它也不会创建任何我们需要支持的新标志。 从长远来看,这应该由构建器处理,只提取它需要的文件并授予对工作目录之外的文件的访问权限(在 #32677 之后两者都成为可能)。 在此之前,我们可以通过重用他们已经设置的-f标志,为在同一源目录中使用不同 Dockerfile 的人们提供解决方案。

@tonistiigi这听起来更复杂和不直观,然后只使用选项来指定忽略文件。 您还需要注意 Dockerfile 的路径,因为它不必位于相应的 .dockerignore 文件所在的同一目录中。 在某些情况下,可以使用具有不同 docker-compose 设置(和不同 .dockerignore 文件)的相同 Dockerfile。 只需添加选项来指定 .dockeringore 就很容易实现并提供最大的灵活性。

@mxl对谁不直观? 该解决方案不提供任何旋钮,因此无法将其搞砸。 如果您认为谁应该定义构建所需/忽略的文件列表(-stage),那么编写构建定义(Dockerfile)的人就是同一个人。 不是调用命令的人。 他们甚至不应该关心这个信息在 2 个文件中,这只是因为这些文件的语法限制。

@tonistiigi我认为这两个选项都应该包括在内,人们会决定什么最适合他们,为什么不呢? 我喜欢你的想法,约定优于配置。

@tonistiigi好的,但它仍然限制为每个 Dockerfile 使用一个 .dockerignore 文件。 但正如我所说,在某些情况下,尤其是 docker-compose,需要使用具有相同构建上下文但不同 .dockerignore 文件的相同 Dockerfile。

@mxl具有不同上下文的相同 dockerfile? 这似乎是一个非常奇怪的情况,读者不可能理解构建时实际发生的事情。 你能举个例子吗? 对于多个 Dockerfile 使用相同上下文的情况,总是存在符号链接,这些情况可能会转而使用构建阶段(下一个版本中应该支持组合)。

@tonistiigi我手头没有真实的例子,但想象一下你有包含文本文件的目录。 Docker 接收这些文件作为构建上下文,除了那些在忽略文件中指定的作为参数传递给docker build的文件。 启动的容器运行 bash 脚本,该脚本从这些文件中随机选择单词并将其打印到输出。
我主要担心的是,目前我们限制每个目录使用单个.dockerignore文件,如果多个 docker-compose 服务使用相同的目录作为构建上下文,那么它们就会发生冲突,因为通常不同的服务需要不同的文件子集从那个目录。
通常不同的服务有不同的 Dockerfile(当需要相同 Dockerfile 的不同 .dockerignore 文件时,我还没有遇到实际情况)所以你的解决方案也适用于我,但我仍然认为它过于限制和隐含。 应该记住 .dockerignore 文件名应该以 Dockerfile 名称开头,如果他重命名 Dockerfile 比他还必须重命名 .dockerignore 文件。

@tonistiigi构建包含静态文件(css、js、gif 等)的 docker 映像(用于开发构建)而不是(用于带有 cdn 的阶段/生产的发布构建)。

@iavael这听起来像是一个奇怪的设置,通常应该将构建生成到项目根目录下的独立构建文件夹中,例如,这是您在 Dockerfile 中为发布构建指定包含COPY命令的内容. 包括整棵树然后一一添加忽略是自找麻烦。

@tonistiigi你说的有道理,我对这两种方法都不知道,但你有一点

这种方法的优点是它不鼓励创建仅在将某些特定选项传递给 docker build 时才有效的 Dockerfile

在基于 Dockerfile 的预解析将构建上下文发送到守护程序之前,修剪构建上下文的状态是什么? 是否有单独的讨论?

应该记住 .dockerignore 文件名应该以 Dockerfile 名称开头,如果他重命名 Dockerfile 比他还必须重命名 .dockerignore 文件。

现有命名方案没有变化。 99% 的人仍应将.dockerignore与任何Dockerfile名称一起使用。 如果您想对其中一个文件进行例外处理,您只能开始使用新的命名方案。

在基于 Dockerfile 的预解析将构建上下文发送到守护程序之前,修剪构建上下文的状态是什么? 是否有单独的讨论?

一旦 #32677 被合并,这将是一个非常小的更新。

@tarikjn对于 python 项目,这是典型的。 您安装系统 deps,复制源代码目录,运行pip install -r requirements.txt并准备就绪。 我看到你有 ruby​​ 的背景,这里应该与 bundler 类似,而不是“pip install”。

我很想在构建中指定多个 dockerignore 文件。 我的用例是我有几个 .gitignore 文件:

1) $HOME/.gitexclude
2) $REPO/.gitignore (而且你可能有子目录也包括一个 .gitignore)
3) $REPO/.git/info/exclude

虽然我希望 docker 包含一个尊重多个 gitignore 的函数,但如果我能做到这一点,它可以让我的生活更轻松:

#!/usr/bin/env bash

git check-ignore -v **/* * | \
    awk '{print $1}' | \
    sort -u | \
    awk -F\: '{print $NF}' | \
    sed -e 's/\/$/\/**/g' | \
    >> .dockerignore.local

然后根据我拥有的任何 gitignore 文件包含 repo 范围的 dockerignore 文件和我自己的自定义 dockerignore 文件。 因为我不想将我的本地 dockerignores 提交到主仓库中,所以我为所有项目使用 .git/info/excude 和通用 gitignore 文件。

也许支持像 git ls-files 这样的语法,它会让我很开心:)

我只阅读了部分回复,但加入此功能也与我有关,与以下 SO 帖子中描述的用例相同: https ://stackoverflow.com/questions/40904409/how-to

我需要一个已部署容器的构建(忽略测试和其他与产品无关的文件),还需要一个用于运行测试的单独容器。 每个实例将共享相同的 Dockerfile,但使用唯一的 docker-compose 文件,指定二进制值是使用 .dockerignore 还是最好应用哪个 dockerignore 文件名。

只是一个想法。

也许我们可以更改 .dockerignore 的搜索逻辑,即从构建上下文的同一目录级别查找文件到 Dockerfile 的同一目录级别。

此更改与原始 dockerfile 代码库目录结构没有什么不同。

但也可以解决多个子项目的情况,只需将您的 .dockerignore 放在您的子目录中。

@tristanz也许您可以描述此功能的一些用例,它可以帮助维护人员做出有根据的决定,无论这是否是想要的东西

我的用例是我们有几个项目,我们现在使用 docker 来构建项目。 为此,我们有一个.dockerfile 。 构建在build/目录中生成大文件,这显然被忽略了,因为构建项目我们不需要我们将要构建的构建文件。

现在我们想用生成的二进制文件构建镜像,这样我们就可以使用 docker-compose 对所有项目进行系统集成测试。 运行时要求与构建要求非常不同,因此我们为此使用不同的 Dockerfile,但为此我们需要build/目录来构建运行映像,它将发送生成的二进制文件。

如果没有选择.dockerignore文件的选项,我们需要为构建映像包含庞大的build/目录,或者包含构建运行时映像的庞大源。 现在我们可能会编写一个包装脚本,在构建每个图像之前将Docker-build.ignore复制到.dockerignore并同样使用Docker-runtime.ignore ,但这种解决方案远非理想。

似乎很有意义,如果有办法选择不同的 dockerfile,那么也应该有办法选择不同的 dockerignore 文件。

@thaJeztah我一直在阅读有关 .dockerignore、构建上下文、构建卷、构建机密等的所有这些问题。看起来这是一个涉及许多不同问题的讨论。 参与讨论的最佳地点在哪里。 我看到了您关于构建套件的评论https://github.com/moby/moby/issues/2745 。 这些讨论正在向前推进吗?

我觉得能够控制构建上下文并为构建器提供 ssh 转发、机密等内容将是向前迈出的一大步。 现在我很多人只需要编写脚本和 hack 来解决对公共 docker 使用有意义但对企业 docker 使用没有意义的约定。 这些问题是意识形态问题还是技术问题?

这不是一个_单一_的答案; 让我试着详细说明一下:

BuildKit 是一个开发全新“构建引擎”的项目(https://github.com/moby/buildkit)。 buildkit 引擎提供底层特性来支持构建器,它可用于从 Dockerfile 构建(如果集成到 Docker 中)并生成 Docker 映像,但也可用于构建源文件并生成二进制文件.

集成到 Docker 中时如何公开这些功能是一个单独的讨论; 有一些优化可以开箱即用(例如,更智能的缓存),但其他功能可能仍需要“连接”才能公开它们

任何更新?
我也需要这个选项。

从构建上下文的同一目录级别到 Dockerfile 的同一目录级别的忽略文件。 +1

任何进展?

  • 为此...或任何方式说--dockerignore=.gitignore

@damianobarbati我认为对于你的情况ln -s .gitignore .dockerignore会做:)

我需要这个,因为有多个构建上下文(在 docker-compose 中也是如此,所以 'ln -s' 解决方案对我不起作用)

我非常需要这个。
无法想象为什么我们有-f选项,但忽略--ignore-file

1+ for --ignore-file

或者,在根本不需要上下文时更好, --no-context (??)

我有一个需要构建多个图像的 monorepo,但我只能有一个.dockerignore文件,因此很难使构建有效。 鉴于 monorepos 越来越受欢迎,这个问题似乎更加有用。

@jonaskello

我有完全相同的问题。 带有 6 个 dockerfile 的 Mono 存储库。 发送给每个的上下文 > 8GB。 :-(

我想要这个功能,因为.dockerignore功能不符合它的规范(即损坏)。

此外,我想指出,目前存在的.dockerignore功能是一个完全的设计失败(正如每个人都在抱怨它所证明的那样)。 它与-f等其他 CLI 选项不一致。

我有一个.dockerignore文件,其中只有.git作为上下文目录中的内容,但是有或没有 .dockerignore 文件的图像大小没有区别(这应该是不可能的)。 我正在使用上下文目录的绝对路径,以防与当前工作目录不同。

当您添加回归测试时,请通知我。

https://gist.github.com/tzickel/2111dd013d1c4f8c765a538e74646f95

如果您不介意使用 python 和 .gitignore 语法(除非有人想将 .dockerignore 支持添加到 python 的 pathspec 库,尽管它们并没有太大区别)这个脚本可以处理 .gitignore 文件的多个路径以从基本上下文中忽略路径(也可以显示发送了哪些文件)。 不要忘记阅读脚本顶部的评论。

当您在同一个 repo 上有许多 docker 构建时,.dockerignore 应该只包含所有构建中应该忽略的内容,但考虑到将来应该有新的 dockerfile 来添加整个 repo 并且需要一些文件之前,这不是一个好习惯忽略。
例如:我有一个构建容器和一个运行时容器,有些东西应该在构建容器上进行,而不应该在运行时容器上。
我们需要一种 .dockerignore 的级联层次结构,添加一个忽略 dockerignore 条目似乎真的是一个疯狂的解决方法。

https://github.com/moby/moby/issues/37129对于必须从同一源/存储库构建多个 Dockerfile 的情况可能是一个很好的解决方案

当前的解决方法是什么?

投票给--忽略

@mitmerayer https://github.com/moby/moby/issues/12886#issuecomment -430502559 是一个选项。

@mitmerayer #12886(评论)是一个选项。

这是一个非常hacky的解决方法。 确实需要添加一个标志以允许 docker 忽略文件的不同名称/路径。 我们的生产和本地开发构建有不同的上下文需求。 目前我们不得不浪费时间/空间在本地构建完整的生产版本,即使我们要安装大部分东西。

虽然我对 Docker 代码库一点也不熟悉,但我不认为这是一件很难添加的事情,而且它当然有它的好处。 它根本不值得添加,还是只是一个非常低的优先级?

我正在使用要点来完成这项工作,但我确实认为如果像 falnos 评论的那样内置标志会更好。

我使用的另一个(一个衬里)工作是手动将上下文与 tar 捆绑在一起并将其管道传输到构建:

# Manually build our context... this is hacky but docker refuses to support symlinks
# or selectable .dockerignore files
tar ch --exclude-from=.dockerignore * | docker build Dockerfile

此评论的解决方案(上面的 PR)已合并并已登陆 Docker 19.03! :火花:

您需要启用 BuildKit 模式才能使用它,例如:

~~~ 猛击
$ 出口 DOCKER_BUILDKIT=1

$ echo "FROM ubuntu \n COPY .tmp/" > Dockerfile
$ cp Dockerfile Dockerfile2
$ touch foo bar
$ echo "foo" > .dockerignore
$ echo "bar" > Dockerfile2.dockerignore

$ docker build -t container1 -f Dockerfile 。
$ docker build -t container2 -f Dockerfile2 。

$ docker run container1 ls tmp
Dockerfile
Dockerfile2
Dockerfile2.dockerignore
酒吧
$ docker run container2 ls tmp
Dockerfile
Dockerfile2
Dockerfile2.dockerignore

~~~

@tonistiigi关于何时将该功能移植到默认构建器的任何估计?
是否会接受对 docker/cli 的 PR?

@jmendeth根据路线图有效地冻结了遗留构建器中的功能开发。 如果 PR 很简单并且不增加维护成本,它可能仍然会被接受。 尽管在某些边缘情况下,将忽略的文件放在上下文中并在守护进程端删除,但为遗留构建器实现这一点可能会有些棘手。

由于https://github.com/moby/buildkit/pull/901是前端,它仅适用于当前版本的 Docker 以及更新的#syntax 。 还没有发布版本,但# syntax=docker/dockerfile-upstream:master # syntax=docker/dockerfile-upstream:master-experimental应该可以工作。

如果我们还可以获得一个标志(例如--ignore )来指定我们想要的任何文件,那就太好了......☺️

@jmendeth根据路线图有效地冻结了遗留构建器中的功能开发。 如果 PR 很简单并且不增加维护成本,它可能仍然会被接受。 尽管在某些边缘情况下,将忽略的文件放在上下文中并在守护进程端删除,但为遗留构建器实现这一点可能会有些棘手。

我明白了,谢谢!

这会在下一个稳定版本中解决吗?

为这个+1(天哪,4岁的问题)。

我们有两个 docker 文件( Dockerfile.devDockerfile.prod )。 开发工具将带有源代码的卷安装到已经构建的容器中,这便于编码,但由于我们不能忽略生产映像中的node_modules ,因此我们也被迫将它们推送到开发映像(在构建期间),这会增加约 200mb 的开销(并且完全没有必要)。

.dockerignore.dev.dockerignore.prod作为单独的文件会非常好。

@ddnomad这里的用例相同。 开发 dockerfiles 不需要在 CI 构建期间播种任何上下文,生产播种应用程序。

不要介意为开发人员和 CI 设置最低 Docker Desktop 版本——只是想知道如何让它工作以及需要什么版本。 目前正在开发中使用:
image

@virgofx对于我们的用例,它还不是世界末日(直到上下文将超过 1GB,哈哈)。

我认为吸收它并花一些时间在不同类型的构建期间动态生成.dockerignore从长远来看可能是有意义的。 可以是make目标或其他东西的一部分。

可怕的骗局,但我侦察就足够了。 显然需要忽略.dockerignore git,否则可能会导致 VCS 混乱。

像这样的东西(+prod 版本,将.dockerignore.prod复制到.dockerignore )。

.PHONY dev-docker-build
dev-docker-build:
    cp .dockerignore.dev .dockerignore
    docker build . \
       -t $(DOCKER_TAG)-dev-$(DOCKER_VERSION) \
       -f Dockerfile.dev

请参阅https://medium.com/@tonistiigi/advanced -multi-stage-build-patterns-6f741b852fae 了解如何使用构建参数在不同的文件集之间切换

请参阅https://medium.com/@tonistiigi/advanced -multi-stage-build-patterns-6f741b852fae 了解如何使用构建参数在不同的文件集之间切换

问题在于请求唯一参数以指定单独的.dockerignore文件......不是多阶段构建模式或参数化构建。

@ddnomad是的 --- 那会工作......不是很干净。 我以为他们已经将其添加到基线中? 只是想知道它什么时候可用?

是的 --- 那会工作......不是很干净

@virgofx viva la hax 🤣

只是想知道它什么时候可用?

大约在docker images ls将停止输出空表的时候我侦察🌚

@thajeztah我认为我们可以关闭它,因为用例已在 19.03 中解决,并且这里有很多过时/不正确的建议可能会使新读者感到困惑。

这已通过三个功能解决:

  • 如果存储库包含很多, https: //github.com/moby/moby/issues/12886#issuecomment -480575928 允许为每个 Dockerfile 设置一个 dockerignore 文件。 (请注意,这是最初问题的准确描述)
  • BuildKit 自动忽略不使用的文件,自动消除不同组文件需要相互忽略的问题。
  • 同一个 Dockerfile 对不同的构建“模式”(例如 dev 与 prod)使用不同的文件集的情况可以通过多阶段构建和使用构建参数定义模式更改来实现。

这与此处最初请求的语法不同,因为该版本与用户期望从 Dockerfiles 获得的稳定性保证不兼容。 所提供的解决方案为需要更好地控制被忽略文件的用户解决了问题,而无需向其他文件添加新文件。

拥有此功能会很棒,在我的场景中,我有 4 个不同的图像要在管道中构建,但是我有一个 monorepo,并且必须将 repo 的根用作基本路径。

已经尝试在构建每个映像之前动态生成 .dockerignore,但是同步 4 个并行构建阶段很痛苦,因为它们同时使用相同的基本路径,并且在尝试获取正确的 .dockerignore 文件时会变得一团糟。

@marcovergueira 有什么问题? 您可以为每个 Dockerfile 指定一个 dockerignore ...该功能已经存在

我将关闭这个问题,因为我认为应该解决所有用例https://github.com/moby/moby/issues/12886#issuecomment -518843764

我_高度_建议启用 buildkit,因为它解决了与上传构建上下文相关的相当多的性能问题(即使不必使用.dockerignore文件);

通过设置DOCKER_BUILDKIT=1环境变量来启用 buildkit

export DOCKER_BUILDKIT=1

这感觉很奇怪......为什么我们不能每个 dockerfile 只拥有 1 个 dockerignore 文件? 默认情况下,每个目录已经有 1 个 dockerfile。 这在 imo 中表现得不合理......使用 docker-compose --build 构建的每个服务都应该使用 dockerfile 构建上下文中的 dockerignore 文件。

@thaJeztah这是否意味着我可以执行以下操作:
sudo docker build --no-cache -t specific_img -f Dockerfile-specific_img 。

并且在构建 specific_img 时,它将使用名为“Dockerfile-specific_img.dockerignore”的文件来确定要从 specific_img 的构建中省略哪些文件?

我在任何地方的文档中都找不到这个…… @jmendeth的评论对我来说并不是很清楚,所有的回声都是如此。
谢谢!

这是否意味着我可以执行以下操作:
sudo docker build --no-cache -t specific_img -f Dockerfile-specific_img 。

并且在构建 specific_img 时,它将使用名为“Dockerfile-specific_img.dockerignore”的文件来确定要从 specific_img 的构建中省略哪些文件?

是的。 如果您执行docker build <file> ,那么将使用<file>.dockerignore而不是.dockerignore (如果存在)。

这感觉很牛逼……

如果还没有的话,总有一天它会成为默认值。

这是否意味着我可以执行以下操作:
sudo docker build --no-cache -t specific_img -f Dockerfile-specific_img 。
并且在构建 specific_img 时,它将使用名为“Dockerfile-specific_img.dockerignore”的文件来确定要从 specific_img 的构建中省略哪些文件?

是的。 如果您执行docker build <file> ,那么将使用<file>.dockerignore而不是.dockerignore (如果存在)。

这感觉很牛逼……

如果还没有的话,总有一天它会成为默认值。

默认意思是不需要“export DOCKER_BUILDKIT=1”? 当使用“export DOCKER_BUILDKIT=1”时——你推荐把它放到我们的 Dockerfile 中吗?

不,不需要放在 Dockerfile 中; 你可以在你的 shell 中设置它(或者,例如,在你的.profile中)来为你的构建启用 buildkit

是否有计划何时将 buildkit 实现作为默认实现?

@matteocontrinihttps://github.com/moby/moby/pull/38738之后

编辑:请注意,如果您不喜欢设置环境,BuildKit 当前也可以在守护程序级别设置默认值。

截至 2019 年 10 月 10 日,这是我观察到的行为(我在任何地方都找不到它的记录)

  • 如果不存在Dockerfile2.dockerignoredocker build -f Dockerfile2将使用.dockerignore
  • docker build -f Dockerfile2将使用Dockerfile2.dockerignore如果它存在。 它不合并 2 个文件的内容。 即Dockerfile2.dockerignore不继承.dockerignore中的内容

只是提醒是否有人对此脚本感兴趣:
https://gist.github.com/tzickel/2111dd013d1c4f8c765a538e74646f95

此功能是否记录在任何地方? 我在 docker compose 中使用它时遇到问题。


更新,关于撰写:据我所知,从撰写中使用它需要将一些不同的东西放在一起:

  • 需要启用 buildkit,这也需要daemon.json experimentaldaemon.json
...
   "experimental": true,
   "features": { "buildkit": true }
...

@jamiejackson是的,不幸的是,docker-compose 功能还没有在候选版本中; 我问了一些撰写维护者是否有计划削减 1.25.0-rc3

@Graham42 ,也许在这里? https://docs.docker.com/engine/release-notes/#19030

查找 Dockerfile 特定的 dockerignore 文件(例如,Dockerfile.dockerignore)以获取忽略的路径。 码头工人/引擎#215

@thaJeztah Windows 用户呢? Buidkit 看起来很棒,但它在 Windows 上不可用,而且支持似乎很遥远。 正如很多人之前讨论的那样,缺少的功能可能会很烦人,它基本上使 docker-compose 在我的情况下无法使用(大型 monorepo)。

我应该提出一个新问题还是我们在这里讨论它?

在某些特定环境标志下将单个功能从 buildkit 反向移植到旧版构建系统(如 windows)是否可以接受?

@guillaume86引用@tonistiigi

根据路线图,遗留构建器中的功能开发被有效地冻结。 如果 PR 很简单并且不增加维护成本,它可能仍然会被接受。 尽管在某些边缘情况下,将忽略的文件放在上下文中并在守护进程端删除,但为遗留构建器实现这一点可能会有些棘手。

@tonistiigi我有一个非常合理的-i/--ignore-file用例,但 19.03 中的新功能未涵盖该用例:从标准输入指定 Dockerfile。 为了安全起见,我正在容器化的代码安装在只读文件系统上。 我通过标准输入传递我的 Dockerfile,但我根本无法提供 Dockerignore 文件。 用于指定 Dockerignore 的命令行参数将是解决此问题的简单易行的方法。

@jonathan-marcus 嗯,如果您无法为动态创建的 dockerfile 编写文件并且需要为此使用 stdin,您将如何编写与您的 Dockerfile 匹配的忽略文件,您可以用新标志指向什么? 我认为期望临时文件可以写入系统并不是没有道理的。 事实上, -f -不能保证在无法创建临时文件的系统上工作。 至少在某些情况下,它的工作方式是将标准输入写入/tmp ,然后从那里共享到构建守护进程。 有一个问题,为了扩展安全性,我们可能会在未来开始为所有构建执行此临时复制步骤,即使没有-f -

大多数文件系统都是可写的; 包含构建上下文的部分是唯一以只读方式安装的部分。 所以我能够在任何地方编写临时文件。 我希望能够通过--ignore-file /tmp/dockerignore 。 我只是无法在构建上下文中的任何地方编写该 dockerignore 文件。

我的用例:我正在部署一个(除其他外)容器化用户代码的程序。 它本身在容器中运行,并使用 Docker-in-Docker 来访问用户的文件系统。 我在外部文件系统上对目标路径进行只读挂载,然后我的程序从容器内运行docker build

@jonathan-marcus 那你可以

d=$(mktemp -d)
cat - > $d/Dockerfile
mv /tmp/dockerignore $d/Dockerfile.dockerignore
docker build -f $d/Dockerfile .

聪明的! 这会很好地工作,谢谢。 我会尝试一下,让你知道它是如何工作的。

根据路线图,遗留构建器中的功能开发被有效地冻结。 如果 PR 很简单并且不增加维护成本,它可能仍然会被接受。 尽管在某些边缘情况下,将忽略的文件放在上下文中并在守护进程端删除,但为遗留构建器实现这一点可能会有些棘手。

@tonistiigi所以我看了一下添加.dockerignore 对遗留构建器的支持,我有一些问题,你能帮忙吗?

“docker/cli”中需要更改,但根据选择,moby/moby 中可能不需要更改。 这是我的两个选择:

  • 在 cli 中,将 pathToDockerfile.dockerignore 与构建上下文一起发送并在构建器端进行处理,因此此处也需要进行更改,并且将功能隐藏在 ENV 变量后面似乎很复杂(需要将信息从 cli 传递给 docker)

  • 在 cli 中,将 tar 存档中的 pathToDockerfile.dockerignore 重命名为 .dockerignore(如果确实存在),此处不需要更改,并且隐藏在 env var 后面是微不足道的

你觉得我应该走哪条路?

当 Dockerfile 包含# syntax = docker/dockerfile:1.0-experimental行时,它似乎不起作用 - 这是已知的限制还是错误?
如果存在此行,则始终使用常规.dockerfile

更新:有趣的是,当我使用# syntax = docker/dockerfile:experimental (没有1.0 )时,它可以正常工作。

@fabb这是在 1.0 之后添加的https://github.com/moby/buildkit/pull/901/commits/7ac4bf072f86891203a05f46f9de16f68fc2ffe6显示了拥有它的标签。

好的,既然该功能已经存在,请详细记录它,并提供以下变量不同组合的完整示例:

  • dockerfile 的位置
  • dockerfile 的名称
  • 构建上下文根

并展示以下问题的正确答案:

  • dockerignore 文件应该放在哪里?
  • dockerignore 文件应该如何命名?
  • dockerignore 文件中的路径应该如何指定(即相对于什么基本路径)?

如果您查看描述和测试中最后一条@tonistiigi消息(https://github.com/moby/buildkit/pull/901)中的 MR,您将看到文件的命名方式和位置放置。
您可以与项目合作并自己进行练习并在同一线程中分享您的所有发现,而不是要求详尽的文档来回答您的所有问题。

正如 repo 描述中提到的,这是一个协作项目,我们都可以帮助使这个项目变得更好:)

询问文档并不是一件坏事。 没有人愿意挖掘问题和 PR 以找到解决方案。 而且它足够相关,可以包含在文档中,以便每个人都可以通过一些清晰的示例访问它。

您可以与项目合作并自己进行练习并在同一线程中分享您的所有发现,而不是要求详尽的文档来回答您的所有问题。

废话。 从问题和 PR 中逆向工程未记录的功能正在追逐云。 只要功能——无论是它的存在还是确切的语义——没有记录,就不能保证这项工作的结果在第二天早上仍然有效。 未记录的功能或未记录的功能方面可以随时更改。 它们不能被依赖或用于严肃的项目。 文档不仅仅是“这是如何工作的”。 这也是“我们承诺它将继续按描述工作”,并且该承诺只能由软件作者单方面做出。 项目的这个方面不是协作的。

如果您查看上一条@tonistiigi消息中的 MR

什么是MR?

构建和使用 dockerignore 文件路径的Build方法是我从未编写过的编程语言中的一个 344-LOC 怪物,使用的是我完全不熟悉的复杂 API。 我不应该解析这段代码。

什么是MR?

“合并请求,”我猜。 GitLab 和 Bitbucket 中“拉取请求”的同义词。

@tonistiigi我终于能够从 4 月开始尝试您的建议,并且它在我的机器上运行良好(Mac 上的 Docker 19.03.12)。 在我同事的机器(CentOS 上的 Docker 19.03.12)上它不起作用。

我们的设置:

/dir/.dockerignore
/dir/.git
/dir/<lots of other contents>
/tmp/Dockerfile
/tmp/Dockerfile.dockerignore

命令: DOCKER_BUILDKIT=1 docker build -f /tmp/Dockerfile /dir

构建上下文 ( /dir/.dockerignore ) 中的 .dockerignore 使用**/.git行排除 .git 目录。 我的自定义 .dockerignore ( /tmp/Dockerfile.dockerignore ) 是原始的克隆,最后加上覆盖!**/.git行。

我的(期望的)结果是生成的图像具有.git目录。 来自我同事计算机的相同命令(不受欢迎)会生成一个没有它的图像。

这个功能是否应该允许我覆盖已经在构建上下文中的.dockerignore ? 你有什么想法为什么我会从我的同事那里得到不同的结果? 我使用docker --version来检查版本,但我怀疑还有其他相关部分我没有检查。

如果有必要,我可以处理一个更简单的可重现示例,并可能提交一个新问题。

这个功能是否应该允许我覆盖已经在构建上下文中的 .dockerignore ?

是的,将使用Dockerfile.dockerignore代替默认的.dockerignore

我使用 docker --version 检查版本

确保检查docker version的输出,因为docker --version只会显示 docker CLI 的版本,而不是守护进程的版本

谢谢,我觉得我在这个版本中遗漏了一些明显的东西。

我上线了:

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:49:27 2020
  OS/Arch:          linux/amd64
  Experimental:     false

我的同事在:

Server: Docker Engine - Community
 Engine:
  Version:          18.09.1
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.6
  Git commit:       4c52b90
  Built:            Wed Jan  9 19:06:30 2019
  OS/Arch:          linux/amd64
  Experimental:     false

此功能所需的最低版本是多少? 我想自动检测并提醒我的用户升级。 我猜是 19.03,因为https://github.com/moby/buildkit/pull/901于 2019 年 3 月合并。

旁注:我的同事很惊讶 CentOS 上的dnf没有通知他升级 Docker,因为他是一个主要版本。

此功能所需的最低版本是多少?

是的,那就是 Docker 19.03.x。 旧版本的 docker 已达到 EOL,因此不再维护。

旁注:我的同事很惊讶 CentOS 上的 dnf 没有通知他升级 Docker,因为他是一个主要版本。

有趣的; 不知道为什么新版本不会出现

我可以确认升级解决了这个问题。 谢谢您的帮助!

@rulatir -- 感谢您代表用户进行宣传。
我仍然在这里追云,但我希望很快能赶上它们:upside_down_face:

此评论的解决方案(上面的 PR)已合并并已登陆 Docker 19.03! ✨

您需要启用 BuildKit 模式才能使用它,例如:

$ export DOCKER_BUILDKIT=1

$ echo "FROM ubuntu \n COPY . tmp/" > Dockerfile
$ cp Dockerfile Dockerfile2
$ touch foo bar
$ echo "foo" > .dockerignore
$ echo "bar" > Dockerfile2.dockerignore

$ docker build -t container1 -f Dockerfile .
$ docker build -t container2 -f Dockerfile2 .

$ docker run container1 ls tmp
Dockerfile
Dockerfile2
Dockerfile2.dockerignore
bar
$ docker run container2 ls tmp
Dockerfile
Dockerfile2
Dockerfile2.dockerignore
foo

嗨,此解决方案有效,但不适用于 docker-compose 命令。
当您使用自定义 Dockerfile(例如 Dockerfile-PROD)和自定义 .dockerignore(Dockerfile-PROD.dockerignore)并在 docker-compose.yml 中链接 Dockerfile 名称时,无法读取 Dockerfile-PROD.dockerignore。

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