Moby: 允许将 dockerfile 指定为路径,而不是管道输入。

创建于 2013-10-08  ·  160评论  ·  资料来源: moby/moby

能够指定docker build -t my/thing -f my-dockerfile .这样我就可以添加文件,并且还有多个 dockerfiles 会很好。

最有用的评论

所以它是docker build -f Dockerfile.dev . ? 编辑:是的

所有160条评论

我只是在调查这个

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

所以如果你跑

docker build -t my/thing my-dockerfile

抱怨 tar 文件太短。

在我看来,'PATH' 选项没有被文档化,所以它可能有一些遗留的含义?

所以 - 我想知道是否检测 PATH 是否是文件,而不是 Tarfile。

就我个人而言,我有一组用于测试的 Dockerfile,并且更愿意将它们全部放在一个目录中并且还具有完整的上下文。

该 PATH 指的是一个目录,而不是特定的 Dockerfile。

哦,然后将 Tars 该目录发送到服务器 - 很酷!

因此可以检测到 isafile,将其所在的目录压缩,然后用指定的文件替换该 tarball 中的 Dockerfile。

或者以相同的方式使用 -f - 允许您的 Dockerfile 定义与有效负载分开

现在弄清楚测试是如何工作的,尝试一下,看看它是否适合我

它不会压缩任何东西 - PATH 是一个目录,其中假定存在Dockerfile

这不是它对 PATH 所做的全部 - 读取代码,“上下文”通过对目录进行去皮处理发送到服务器。

(好吧,所以我仍然不知道去,而且我只在最后几分钟阅读了代码,所以持怀疑态度)

正确,因此通过 ADD 引用的任何非远程文件也必须位于同一目录中,否则守护程序将无法访问它们。

啊,我明白你在说什么 - 是的 - 这正是我想要的 - 一种用 -f 指定 dockerfile 的方法,然后是可能分开的目录 PATH。

所以我可以:

docker build -t my/thing fooproj
docker build -t my/thing -f debug-dockerfile fooproj

2108(向 Dockerfiles 添加一个 include 指令)添加了一个有趣的皱纹

应该包含相对于指定的 dockerfile 或 PATH。 不过还不重要。

乐趣:

docker build -t my/thing fooproj
docker build -t my/thing -f ../../debug-dockerfile fooproj
docker build -t my/thing -f /opt/someproject/dockerfiles/debug-dockerfile fooproj

作为额外奖励 - 还没有 CmdBuild 测试,所以猜猜我首先要学习什么:)

@SvenDowideit你在做这个吗? 我在想今天可能会破解它

我慢慢地让自己熟悉了代码并开始了,所以去吧 - 我只是编写单元测试太有趣了(也许你可以使用测试提交来帮助:)

我会做 :)

我也想看看这个功能。 我们有一个可以在 3 种不同模式下运行的系统,我们想部署 3 个不同的容器——每个模式 1 个。 这意味着 3 个几乎相同的 docker 文件,只是 CMD 不同。 但是由于路径只是目录,而目录是 ADD 命令的上下文,我现在无法让它工作。

所以:我+1!

看起来这可能与 #1618 具有相同的最终目标(尽管使用不同的方法)。 这里的想法是使用一个带有多个TAG指令的单个 Dockerfile 来生成多个图像,而不是使用多个 Dockerfiles 和一个包含系统,如这里所述。 想法?

似乎如果您可以通过管道输入 Dockerfile,您也应该能够指定路径。 有兴趣看看 #1618 会带来什么,但我认为这提供了更多的可能性。

这就是我所在的位置: https :

我被文档没有明确说明包含 Dockerfile 的目录是构建上下文这一事实所抛出的 - 我错误地假设构建上下文是当前工作目录,所以如果我将路径传递给 Docerfile它在当前目录中,我试图从当前工作目录添加的文件因“没有这样的文件或目录”错误而被炸毁。

我遇到了同样的错误,任何想法

docker 构建 Dockerfile


上传上下文

2013/12/11 21:52:32 错误:错误构建:Tarball 太短

@bscott 改为尝试docker build . 。 构建需要一个目录,而不是一个文件,这就是“构建上下文”。 :)

辛苦了!,我只想在不同的 Docker 文件之间进行选择。

来自我的 +1。

我需要从我的来源创建多个图像。 每个图像都是一个单独的关注点,需要构建相同的上下文。 污染单个 Dockerfile(如 #1618 中所建议的)是不可靠的。 在我的源代码中保留 3 个单独的<image-name>.docker文件对我来说会更干净。

我很想看到这样的东西实现。

这比乍看起来更难实施。 看起来./Dockerfile已经很成熟了。 经过初步调查,至少涉及这些文件:

api/client.go
archive/archive.go
buildfile.go
server.go

client使用archive archive来解压build context build context并将其发送给server ,然后archive使用buildfile

最简单的实现似乎涉及更改clientarchive以使用通过此选项指定的文件覆盖 tar 的./Dockerfile 。 我会进一步调查。

@thedeeno我会很快看一看,然后告诉您是否应该进行更改。 我认为它只是在一个地方。

来自我的+1!

我一直在关注#1618 和#2112,这是最优雅的解决方案。

在我的开发中有一个特殊的用例,该功能非常方便......在处理同时具有“网络”和“工作者”角色的应用程序时。 我想为这种情况创建两个 docker 文件“Dockerfile-web”和“Dockerfile-worker”。 然后我可以构建它们,标记它们,并将它们推送到我的图像存储库。 然后,我将在负载平衡器和多个工作程序后面运行多个 Web 前端实例来处理被推入队列的任务。

+1 作为 #2745 的替代方案。

+1

我惊讶地发现Dockerfile是硬编码的,并且构建上下文被强制为 Dockerfile 的目录,即使使用命令行标志也不能覆盖。 这严重限制了 Docker 作为开发、测试和部署工具的实用性和灵活性。

+1
我很感激这种改变

+1
真的需要这个

5033 应该允许此功能。 抄送/@crosbymichael

@shykes您如何看待这种变化? 我认为您不同意或者可能不知道解决同一问题的更好解决方案。

我很犹豫。

一方面,我不想限制人们自定义构建的能力。

另一方面,我担心会发生与 _run -v /host:/container_ 和 _expose 80:80_ 相同的事情。 换句话说,它将允许 1% 的知道他们在做什么的人添加一个很酷的自定义 - 而另外 99% 的人则非常糟糕。

例如,我们有很多新的 Docker 用户开始使用主机安装的卷而不是常规卷。 我们不得不完全弃用 _expose 80:80_ 语法,因为太多人发布了每个主机不能运行超过一次的图像,没有充分的理由。

所以我的问题是:难道我们不会冒险拥有大量无法使用 _docker build 重复构建的源代码库吗?

_,因为现在你必须阅读一个 README,它告诉你运行一个 shell 脚本,然后运行 ​​'docker build -f ./path/to/my/dockerfile',仅仅因为你不想把 Dockerfile 放在存储库的根目录? 或者也许是因为您是初学者并且只是从非官方教程中复制粘贴了该技术?

能够删除源代码库,并在没有歧义或人工发现的情况下自动构建它是 Dockerfiles 有用的原因之一。 这个拉取请求不会在很多情况下引入闯入的风险,基本上没有充分的理由吗?

@shykes

  1. 我有一个基于 Docker 的构建环境,它生成一个工件(在本例中为 JAR 文件)。 构建环境与运行环境不同(依赖不同,镜像较大等,所以我不想将构建环境继承到运行时。对我来说,拥有Dockerfile构建是最有意义的并围绕 JAR 运行运行时环境。所以我有一个单独的Dockerfile.build文件来构建和运行构建环境并创建 JAR。但是,由于我无法指定 Dockerfile,我不得不创建一个scripts/build文件执行docker build < Dockerfile.build然后使用docker run -v ...挂载主机卷以运行构建(因为我无法使用带管道输入的 Dockerfile 的 ADD)。我想做的只是能够运行docker build -t foobar/builder -f Dockerfile.builddocker run foobar/builderdocker build -t foobar/runtimedocker run foobar/runtime并且只在两个 Dockerfile 中使用 ADD 命令。
  2. 使用 ONBUILD 指令,我希望能够将 Dockerfiles 放入在其 FROM 指令中有根 Dockerfile 的子目录(或根目录中有 Dockerfile.env 等文件),但仍然可以使用项目的根目录作为他们的构建上下文。 例如,这对于为不同环境引入配置参数很有用。 根 Dockerfile 仍然会生成一个有用的容器,但其他容器会创建我们需要的不同变体。

所以我想我真正想要的是能够将“构建上下文”的概念与“Dockerfile 位置/名称”分开。 当然,有很多潜在的方法可以做到这一点,但这对我来说似乎是一个相对简单的方法。

@cap10morgan您是否有机会向我指出您的示例 1 或类似的内容? 所以我可以四处玩,确保我们在谈论同样的事情。

@shykes https://github.com/shykes完全不是便携性的梦想
那图像索引是干什么用的? 为什么需要构建环境
也便携?

一些构建过程需要的不仅仅是香草所能做到的
文件。 此外,每个上下文强制执行一个 Dockerfile(这就是
此请求旨在修复)非常有限。

这确实影响了我们的团队。 在我们的设置中,我们想生产多个
来自相同“上下文”的图像。 通过添加--file选项,我们可以做到
我们真正想做的 - 即添加foo.dockerbar.docker
进入我们的存储库根目录。 相反,我们最终编写了 bash 脚本来复制
将大量文件放入临时位置以建立上下文,并重命名我们的
将命名的 docker 文件放入魔法Dockerfile ,这样docker build就可以
工作。

对我来说,这些箍的存在没有充分的理由。 如果我们团队中有人想要
为了构建我们的图像,他们需要运行自定义脚本来完成工作 -
您认为可以通过坚持此限制来避免的确切事情。

在星期一,2014年4月7日在下午4时23分,所罗门Hykes [email protected]

@cap10morgan https://github.com/cap10morgan任何你可以指出的机会
我看你的例子 1,或者一些近似的东西? 所以我可以玩
并确保我们在谈论同一件事。

直接回复本邮件或在Gi tHub上查看
.

@shykes,因为这似乎变得“不会修复”,您能否指出文档或对 Docker 认证方法的解释来处理此问题?

我的用例是我有一个我想用 docker 构建的应用程序,其中测试的要求与生产映像的要求不同。 我认为这是很常见的。

这和 .dockerignore 问题 (https://github.com/dotcloud/docker/pull/3452)(将我的整个 .git 目录复制到构建上下文)是我在尝试 docker 时遇到的第一个关键痛点在过去几天我们的项目中,对我来说似乎没有脑子,但似乎在这些问题上有阻力。

+1 也需要这个 - 我们有一个单一的代码库,其中正在开发多个微服务。 我们希望能够生成多个图像,例如,一个图像包含 services/base/* 和 services/fooservice/* ; 另一个包含 services/base/* 和 services/barservices/* 以及 staticfiles/* 的图像。
我们不能将 Dockerfiles 放在服务文件夹中,因为 Docker 将该文件夹视为上下文,我们无法添加文件夹结构中更高级别的任何内容。 我们不能将两个 Dockerfile 放在 root 中,因为它们具有相同的名称。
我们唯一的解决方案是将 Dockerfile 放在服务文件夹中,然后编写自定义脚本来解析选定的 Dockerfile,确定要添加的路径(所有指定的都相对于项目根目录),然后将它们复制到新的临时文件夹,将选定的 Dockerfile 复制到该新文件夹的根目录,最后运行“docker build tempfolder”。 真的有必要吗?
如果您可以简单地分别告诉“docker build” Dockerfile 在哪里以及上下文在哪里,那将会简单得多。

也遇到这个问题..很想看到某种修复。

+1,围绕这个限制编码是一个巨大的痛苦。

+1 for -f 标志,指定与构建上下文分开的 Dockerfile 路径

Docker 是一个非常棒的工具,但是上下文和特定 Dockerfile 的这种紧密耦合肯定会稍微污染 Docker 团队。 目录结构并不总是准确地反映“容器/子系统”结构。

修复起来有多难? 并且,为此已经有一些 PR,但它们都被忽略了。

一个相关的简单添加是为我们不想添加到上下文的内容创建一个忽略文件 - 是的,我正在看着你,.git ...

这实际上可能会让我暂时跳过 Docker,而回到 Vagrant + Ansible。 好的。

@davber .dockerignore 在 -> #6579

但是,是的,贡献管理现在有点痛苦,这是迄今为止关于 docker 的罕见令人沮丧的事情之一。 我想他们只是有点不知所措。

Docker 团队,人们如何才能审查并加入这样的事情? 如果对为什么这真的很糟糕,以及项目应该如何避免这个问题有一个清晰的想法,我们很乐意听到它,但这似乎是一个简单的问题来描述和解决的简单问题。

/cc @shykes @creack @crosbymichael @vieux

+1 表示 -f 标志。 还有一个 DOCKERFILE 环境变量来覆盖构建设置。

@jakehow是的,肯定有一种不知所措的因素,对于每个维护者来说,至少有 1,000 人积极请求某些东西,并要求详细解释为什么还没有完成。 我们真的尽力了,如果您访问 #docker 和 #docker-dev irc 频道,您将亲眼目睹消防水管。

但是在这种情况下,对于为什么最好保留 Dockerfile 和源目录的 1-1 映射,已经有了明确的答案。 我将再重复一遍:我们希望保留 docker 构建的自描述属性。 事实上,你可以指向一个源代码目录,_没有带外的其他信息_,并根据上游开发人员的规范构建一个镜像,这是非常强大的,也是 Docker 的一个关键区别。

当然,能够动态地将目录 X 与 Dockerfile Y 动态组合起来非常方便(尽管我从来没有觉得有必要使用它,而且我经常使用 Docker)。 但这使得做一些愚蠢的事情变得太容易了 - 即打破你的构建的自我描述性质。 这似乎是一个非常糟糕的权衡。 因此决定不实现此功能。

至于“1 个源代码库,多个图像”示例,是的,我绝对同意这是必要的。 我们需要的是一种 Docker 标准的方式,让单个源目录定义多个构建目标。 这可以使用多部分 Dockerfile 或多个 Dockerfile 来完成_只要有一个明确定义的文件名约定,允许以明确的方式列出和选择这些 Dockerfile_。

如果有人想贡献这个,我们很乐意合并它。 和往常一样,我们很乐意帮助首次贡献者,来 IRC 打个招呼,我们会让你开始。

@davber我的印象是 Vagrant 对每个项目有 1 个描述文件的相同限制(大概是出于类似的原因)。 切换回 Vagrant 将如何准确解决您的问题?

@gabrtv你想尝试把多图像带回来吗? 这是一个初步的建议:

$ ls | grep Dockerfile
Dockerfile
db.Dockerfile
frontend-prod.Dockerfile
frontend-dev.Dockerfile
$ docker build -t shykes/myapp .
Successfully built shykes/myapp/db
Successfully built shykes/myapp/frontend-dev
Successfully built shykes/myapp/frontend-prod
Successfully built shykes/myapp
$ docker build -t shykes/myapp2 --only frontend-dev .
Successfully built shykes/myapp2/frontend-dev

该提案对我们来说效果很好,我可以看到它也为其他人解决了其他问题。

@shykes我不认为我认为增加 Dockerfile 格式的复杂性对于保持一个 Dockerfile 是一种值得的权衡。

以 makefile 为例 - 一个项目有一个“Makefile”比没有更常见,但 make 也允许你用“-f”指定一个不同的 makefile。

我还认为 sourcefolder 和 image 之间的 1:1 映射没有你想象的那么有用 - 我发现生成一个构建文件夹并从中构建以保持复制到上下文中的数据量是很常见的最小,因此图像更小。

你说“所以我的问题是:我们不要冒险拥有大量无法使用 docker build 重复构建的源存储库,”

但我认为情况已经如此,一些项目要求意味着单一的构建方式是不切实际的,而且 Dockerfile 语法不允许大量的可配置性(根据设计,我不希望改变……)。

我也不特别喜欢 --only 建议。 我认为人们在构建时 / 想要 / 的默认设置是针对要构建的特定上下文,而不是所有内容 - 当我运行 docker build 时,我希望 /only/ Dockerfile运行。 但我也希望能够拥有另一个/可以/构建的图像。

根据我的理解,这里的问题在于当
管道 Dockerfile (cat Dockerfile | docker build -) 我们失去了工作
ADD 和 CP 的目录。

将通过为 docker build 添加一个标志来解决这个问题,允许我们
指定源文件夹内容所在的位置?

cat Dockerfile | docker build --cwd=~/my_docker_data_files -

在本提案中, --cwd标志指定了 ADD 和 CP 的基本文件夹
命令。

2014-06-29 19:42 GMT+10:00 彼得布雷登通知@ github.com:

你说“所以我的问题是:我们不要冒险拥有大量资源
无法使用 docker build 重复构建的存储库,”

但我认为已经是这样了,有些项目要求意味着
单一的构建方式是不切实际的,Dockerfile 语法也不
允许大量的可配置性(根据设计,我不想要
改变...)。

我也不特别喜欢 --only 建议。 我认为默认
人们在构建时 / 想要 / 是为了构建特定的上下文,
不是所有的 - 当我运行 docker build 时,我想要 /only/ Dockerfile
运行。 但我也希望能够拥有另一个 /can/ 的图像
建成。


直接回复此邮件或在 GitHub 上查看
https://github.com/dotcloud/docker/issues/2112#issuecomment -47449994。

@llonchj实际上https://github.com/dotcloud/docker/pull/5715解决了这个问题(在某种程度上)并且已经合并到 master。

@shykes肯定会接受另一个多图像 PR,但在查看 #5715 之后,我想知道这个特定的 PR 是否不再相关。

根据@peterbraden的原始评论...

能够指定 [command redacted] 这样我就可以添加文件,并且还有多个 dockerfiles 会很好。

每@cap10morgan...

所以我想我真正想要的是能够将“构建上下文”的概念与“Dockerfile 位置/名称”分开。

这不正是#5715 所做的吗? 据我了解:

$ cd myapp
$ ls Dockerfile
Dockerfile
$ docker build -t gabrtv/myimage
Successfully built gabrtv/myimage
$ ls subfolder/Dockerfile
Dockerfile
$ tar -C subfolder -c . | docker build -t gabrtv/myotherimage -
Successfully built gabrtv/myotherimage

我知道这并不能解决来自 repo 根的多图像构建(我同意这会很好),但是想知道现在是否可以使用 #5715 来停止这个特定的 PR/实现。

@gabrtv在我看来,#5715 不符合@shykes具有始终有效的单个命令的标准。 tar -C subfolder -c . | docker build -t gabrtv/myotherimage -对我来说非常不明显。

此外,它对开发人员在 repo 布局方面施加了烦人的(如果不是繁重的)限制。 并非不可修复,但是“哦,我将不得不重新组织整个存储库”不会帮助任何人说服他们的老板改用 Docker。

我个人非常喜欢@shykes 的最新建议,其中可能有多个 .dockerfile(为什么不只是 .docker?)文件,所有文件都是默认构建的。 这使得无论如何都可以轻松地使用一个命令启动和运行,并在以后进行优化。

根据实现,可以在所有图像中为此只上传一次构建上下文,这将降低构建多个图像的成本。 因为我没有 .dockerignore,我的构建上下文有几百兆字节,我必须等待一段时间才能上传我的上下文,所以这会很好。

@ratrayalex相信我,我同意“拥有一个始终有效的单一命令”的目标。 我很有可能最终会编写代码并提交 PR。 :眨眼:

我的观点是从项目组织的角度来看,我们应该在其他地方进行讨论,而不是在一个名为Allow specifying of a dockerfile as a path, not piping in的旷日持久的问题上进行讨论:

  1. 这里的大部分讨论与https://github.com/dotcloud/docker/issues/2112#issuecomment -47448314 中的@shykes新提案无关
  2. 最初的底层问题(从 Dockerfile 中分离构建上下文)由 #5715 解决,尽管可能不是每个人都喜欢

引用@llonchj...

根据我的理解,这里的问题在于当管道 Dockerfile (cat Dockerfile | docker build -) 时,我们会丢失 ADD 和 CP 的工作目录。

换句话说,如果您对docker build -t <image> -f <path-to-dockerfile> ,您可以使用tar -C <path-to-context> -c . | docker build -t <image> -作为功​​能等效的解决方法,直到我们可以为@shykes提案整合 PR。

我建议我们关闭它并在别处开始新的讨论(邮件列表?新问题?)。

感谢今天参与此问题的所有人:

@shykes感谢您的推理。 我认为我们想要这个(其他人可以插话)的理由是我们的经验:每个应用程序都需要带外信息才能在选定的上下文中运行。 我们所有的应用程序都有多个上下文。 docker build 的结构方式迫使应用程序开发人员将该信息的知识移动到他们的存储库结构中,或者使自定义构建脚本覆盖包含信息的 docker build 的行为。

@gabrtv我认为这里几乎所有的讨论都专门与这个问题有关,很高兴看到它终于在这里得到讨论。 问题的标题和一些“发现”帖子可能有点不相关,所以一个新的问题或公关可以很好地开始引用这个问题。

来自@shykes评论的提议对我来说听起来像是一个解决方案,之前是否有在此方面做过的工作可以参考或查看?

“Dockerfile.frontend-prod”不是更好,以便所有 Dockerfiles
在一个目录中自然排序在一起?

对不起,但这只是愚蠢的。 如果我的 repo 构建了 100 个服务,我当然不想在根目录下有 100 个 Dockerfile。 (例如:dotCloud PAAS 存储库。)

我也不想要一个包含 100 个部分的庞大 Dockerfile。

我想要 100 个 Dockerfile,并且我想要它们在不同的目录中。

(不,我不能只在自己的目录中构建每个服务,因为几乎所有服务都将使用位于每个服务目录 _outside_ 的公共代码和库。)

同样,我不明白为什么有一个额外的标志来指定 Dockerfile 的路径(默认为Dockerfile )是如此重要?

此外,当前的提案 ( <imagename>.Dockerfile ) 根本不符合当前自动构建的设计。 如果我的任何构建系统上的一个存储库遭到破坏,攻击者可能会超载我的所有存储库......?

@jpetazzo喜欢最理性的人,我欢迎分歧,但不喜欢被称为

_再次,我不明白为什么有一个额外的标志来指定 Dockerfile 的路径(默认为 Dockerfile)是如此重要?_

我在上面做了一个具体的论证。 随意阅读它并提出反驳。

回复:杂乱无章。 @gabrtv对 IRC 也有同样的担忧。 经过一番讨论,我们想出了这个替代方案:

$ ls Dockerfile Dockerfiles/*
Dockerfile
Dockerfiles/frontend-prod
Dockerfiles/frontend-dev

相同的想法,但根存储库中的单个文件较少。

此外,目前的提案(.Dockerfile) 根本不符合当前自动构建的设计。 如果我的任何构建系统上的一个存储库遭到破坏,攻击者可能会超载我的所有存储库......?

那么,他们现在如何命名? 如果您有一个名为“abc”的存储库,只有一个普通的 Dockerfile,那么它生成的图像将被命名为“abc”。 如果您有一个包含“Dockerfile.abc”和“Dockerfile.zzz”的存储库“xyz”,那么您可以将这些构建命名为“xyz-abc”和“xyz-zzz”。

我和你一样处于类似的情况(很多服务都在他们自己的子文件夹中,具有共同的部分)和设置 Dockerfile 以在构建时使用的显式选项会让我的思考更容易,但我也可以看到我如何将“Dockerfile.*”提案与已经发布的“tar 文件作为上下文”结合起来以获得我想要的东西——每个服务的根 dockerfiles 将生成它们的构建映像(带有编译器和其他东西),以及当那些运行时,它们会输出一个 tar 上下文,其中包含已编译的可执行文件和一个生产 Dockerfile(取自服务文件夹本身),该文件将描述仅包含运行时依赖项的映像。

事实上,我现在甚至使用单个根 Dockerfile 编写它,因为我的构建环境对于所有服务或多或少都相同,我可以简单地在运行时向它传递一个参数,以告诉它我希望它创建哪个服务发布上下文 tar。

@shykes好吧,如果我们有 Dockerfile/* ,那么为什么不更进一步,让“docker build”简单地在当前目录的所有子文件夹中搜索名为“Dockerfile.*”的文件,递归,然后在当前目录的上下文中运行所有这些? 当我们在 if 时,提供一个选项来构建其中一个......比如“-f”? :)

……不喜欢被人说傻

我不知道“傻”会让人觉得冒犯; 我的意思可能只是“笨拙”,因此为滥用这个词而道歉。

我认为您的具体论点是“我不希望人们开始将 Dockerfile 放在随机的位置,并在不是绝对必要的情况下系统地使用-f ”。 那正确吗? 在这种情况下,在 repo 的顶部指定一个 Dockerfile,列出其他 Dockerfile 是有意义的。 如果该文件不存在,构建器可以拒绝操作(或发出警告),如果它只列出一个 Dockerfile,构建器也可以发出警告。 我不认为-v-p的平行在这里是合适的。

@aigarius如果我们这样做了,那么如何将每个子 Dockerfile 映射到子图像就不那么明显了。 ./Dockerfile.*./Dockerfiles/*的优点是它们映射到单个命名空间,我们可以用它来命名生成的图像。 相比之下,如果我有./foo/Dockerfile.db./bar/Dockerfile.db ,还有docker build -t shykes/myapp . ,哪一个被称为shykes/myapp/db

哪一个被称为 shykes/myapp/db?

两者都不。 在这种情况下,您会将 Dockerfile 的完整路径编码到名称中,因此您将拥有“shykes/myapp/bar/db”和“shykes/myapp/foo/db”。 这 _ 确实_ 令人不安地接近 Java 命名空间,但我会留给其他人来决定这是好是坏。

@shykes :关于 Vagrant,好吧,我,很可能还有很多其他人,将 Vagrant 用于 Docker 的一些重叠功能。 所以,对我来说,我需要确信我当前的多机构建——我在 Vagrant 中做的,有多个机器定义——在使用 Dockerfiles 时不会变得更尴尬。 问题是 Vagrant 中的“上下文”更加灵活,我可以通过共享目录从任何位置即时获取上下文,语言也是如此,所以如果我只想构建一个服务(或机器)我可以设置一个环境变量并对其进行“无业游民”。 我每天都使用这种方法在我的系统中创建或提供一些服务。 而且,如果我对不断增长的 Vagrantfile 感到太恼火,我可以轻松地“加载”一个描述单个服务或方面的子 Vagrantfile。

关于处理多个 Dockerfile 的具体建议,是的,这将使我们能够为单个服务划分我们的逻辑。 伟大的。 但是,我经常想要或需要单独构建一个服务,所以我仍然需要指定一个特定的 Dockerfile...

所以,我的问题有两个方面:

  1. 没有为所有服务获得一个巨大的凌乱文件
  2. 能够在该文件/文件集群中构建一项特定服务

同样,Docker 是一个天才的想法和工具,所以我希望像我这样的人放弃 Vagrant 以获得某些功能或用例。

抱歉,如果我重复上面彻底处理过的内容,但我看不出有什么解决方案比支持“-f”选项更好。 即,由于对驻留在上下文根中的 Dockerfile 的一些根深蒂固的依赖而导致的模实现问题,我认为它没有任何缺点。

使用“-f”选项,您绝对可以随意构建子目录和子 Dockerfile,例如上面的 Dockerfiles/ 方法。 是的,然后需要一个简单的单行basher来模仿确切的行为......

共享和灵活性之间似乎存在紧张关系。

如果共享是最重要的功能,那么是的,标准的 dockerfile
说得通。

我不认为共享是最重要的功能。 共享已实现
通过图像。

此外,我们在明确不可共享的项目上使用 docker。 在
这些案例的灵活性对我们来说更有价值。 听起来像很多
线程 any 都在这个相同的位置。

专用的 -f 选项为我们提供了所需的灵活性。 另一方面,
能够为构建上下文指定绝对路径也将
工作。
2014 年 7 月 3 日下午 6:00,“大卫伯格曼”通知@github.com写道:

对不起,如果我重复上面彻底处理过的事情,但我看不到
有什么解决方案比支持“-f”选项更好。 即,模
由于对某些根深蒂固的依赖而导致的实施问题
Dockerfile 驻留在上下文根中,我没有看到任何缺点
它。

使用“-f”选项,您绝对可以构建子目录
和子 Dockerfiles 随心所欲,例如 Dockerfiles/
上面的方法。 是的,然后需要一个简单的单行 basher 来
模仿确切的行为......


直接回复此邮件或在 GitHub 上查看
https://github.com/dotcloud/docker/issues/2112#issuecomment -47989616。

同意-f以最小的“惊喜”提供最大的灵活性(我个人认为有这样的标志并在进入此线程之前尝试过)。
添加-c ,无论是目录还是 tar,以提供上下文也似乎是一个了不起的补充。 这将从大型构建过程中删除常量cd s,例如; 在公司。

此外,包含docker build -f foo/bar/Dockerfile -c foo/说明的自述文件听起来对我来说并不令人反感。
还同意docker build可以轻松搜索Dockerfile s。 这样,一个回购结构如下:

-- README
-- foo/
---- Dockerfile
---- etc
-- bar/
---- Dockerfile
---- etc
---- subbar/
------ Dockerfile
-- context/
---- etc

将避免任何可能的命名冲突( repo/bar/subbar ),易于推理数量,并且在许多开发环境中应该有意义。 它将允许轻松使用docker builddocker build -f ,后者可以构建许多上下文,而Dockerfile

如果-f是一个文件而不是一个包含 Docker 的目录,那也应该有效,这样开发人员就可以拥有一个在docker build运行时未构建的 dockerfile。

只是为了不要迷失方向,昨天在与@shykes 的IRC 讨论中,他对实现这一点有了另一个想法:

  • 在存储库的根目录中有一个主 Dockerfile,它只包含几行新格式,例如“INCLUDE foo/bar/Dockerfile AS bar-foo”,用于每个要生成的图像
  • 每个子项目(如foo子项目的bar模块),需要一个单独的镜像,在foo/bar/Dockerfile维护一个常规的Dockerfile。 该 Dockerfile 中的路径(用于 ADD 和 COPY)仍然相对于上下文根,它是存储库的根(主 Dockerfile 所在的位置)
  • 定期调用“docker build -t mycorp/myapp”。 将构建在根 Dockerfile 中注册的所有图像,并在此示例中为其分配名称,例如“mycorp/myapp/bar-foo”
  • 需要引入“docker build”的附加命令行选项以仅构建一些声明的图像,例如“docker build -t mycorp/myapp --only bar-foo,baz-db”

以防万一人们仍在寻找解决方法:

#!/bin/bash
ln -s Dockerfile-dev Dockerfile
docker build -t image/name-dev:latest .
rm Dockerfile

@shykes ping? 如果特定设计解决方案获得了核心开发人员的批准,那么更有可能有人会尝试实施该解决方案并提出拉取请求。

+1 到 -f 解决方案,虽然我同意每个 repo 理论上应该部署自己的服务。 有些人没有这种解决方案的奢侈。 我的特殊问题是我有一个包含多本食谱的厨师仓库,我需要能够构建许多服务。 但我需要能够在上面添加目录。 因此,将上下文保持在根目录并指向子目录中的 docker 文件是最佳选择。

由于已经给出的原因,“-f”可能不会被实施。

构建在主机之间完全相同是必不可少的,并且依赖于以特定方式设置主机的东西(即,在某个随机位置的 Dockerfile 和在其他位置的上下文)破坏了这个契约。

我认为 #7115 可能是正确的解决方案

我认为还有 #7204 也适用于此的大部分用例。

我不喜欢涉及向 dockerfile 添加语法的两个建议解决方案。 他们两个都不是直截了当的。 #7115 似乎仍然无法解决我想从单个存储库生成多种类型图像的用例,例如,我在我的一个项目中生成“测试”图像和一个“产品”形象。 #7204 似乎是一个过于复杂的解决方案,它解决了一个不同的问题-f允许 _configurability_ 构建,而这两个解决方案都解决了 _sub_builds_。

我真的很想对“构建在主机与主机之间的工作方式完全相同是必不可少的”进行一些解释。 我不明白为什么这是一个如此关键的原则。

事实上,我正在使用make来生成 docker 环境作为整个问题的解决方法,这似乎已经违反了您的主机到主机运行相同的命令。

对我来说, -f似乎是一个实用的解决方案,但如果它不可接受,那么也许我们可以考虑一个不涉及将 dockerfile 转换为成熟的编程语法的解决方案。

构建在主机与主机之间的工作方式必须完全相同

我也想更多地了解为什么这是关键。 我们的团队目前
被迫编写构建过程的脚本 - 您试图避免的确切事情。

当我从注册表下载图像时,它就可以正常工作。 我不需要
建立它。 这不是实现主机到主机的可重复性吗? 为什么要构建
还必须主机到主机可重复吗?

2014 年 7 月 28 日星期一上午 10:43,Peter Braden通知@ github.com
写道:

我不喜欢这两个提议的解决方案,包括向
码头档案。 他们两个都不是直截了当的。 第7115章
https://github.com/docker/docker/issues/7115好像还是不行
将解决我想生成多种类型图像的用例
从一个单一的回购,例如我在我的一个项目中做的
生成“测试”图像和“产品”图像。 #7204
https://github.com/docker/docker/pull/7204似乎是一个
解决不同问题的过于复杂的解决方案 -f 允许
_configurability_ 构建,而这两种解决方案都针对
_sub_builds_。

我真的很想解释一下“构建工作是必不可少的
从主机到主机完全相同”。我不明白为什么这是一个关键
原则。

事实上,我正在使用 make 生成 docker 环境作为
解决整个问题的方法,这似乎已经违反了您的
主机到主机运行相同的命令。

对我来说,-f 似乎是一个务实的解决方案,但如果它不可接受,
那么也许我们可以想到一个不涉及转动的解决方案
dockerfile 转换为成熟的编程语法。


直接回复此邮件或在 GitHub 上查看
https://github.com/docker/docker/issues/2112#issuecomment -50347483。

据我了解,关键思想是你可以拉一个 git repo,如果你在那里看到一个 Dockerfile,那么你可以执行“docker build -t mytag”。 在其中并获得完整的预期构建。 这里的关键是没有定制的构建说明,人们可能会出错或不知道。
_可能_是一种在单个上下文中定义多个 Docker 镜像的方法,默认情况下,所有镜像都使用预定义的子标签构建,然后您可以选择仅构建许多可能的镜像中的一个。
这样,公共构建语法得以保留,同时还允许:1)从一个上下文生成许多不同的图像; 2)仅选择使用“高级”选项生成其中之一。
建议的语法在我上面的评论中有描述 - https://github.com/docker/docker/issues/2112#issuecomment -48015917

@algarius谢谢,我认为此时我们应该为 _INCLUDE_ 语法打开一个新的设计方案。 有关设计提案的示例,请参阅 #6802 或 #6805。

该过程如下所示:

  • 提交设计方案
  • 讨论设计方案
  • 我批准设计方案
  • 发送设计方案的 PR

老实说,构建现在并不是真正可重复的。

如果我的 Dockerfile 中有RUN apt-get update && apt-get install build-essentials ruby python whatever ,那么我已经受制于
在我构建图像时,repos 中的任何“最新”。 如果
你一周后构建镜像,你很可能会得到不同版本的
对我得到的依赖。

@codeaholics但这取决于您没有挂钩版本,并且完全不受 Docker 的控制。

大概是公正的评论

@codeaholics你是对的,构建的可重复性并不完美,尽管有控制它的选项(比如版本固定),我们应该提供更多。 但至少构建始终具有相同的_入口点_,这意味着我们_可以_引入更好的可重复性。 然而,一旦你的构建依赖于 Docker 本身上游的 3d 方工具,就没有回头路了:你的构建的可重复性基本上为零,而且 Docker 未来的任何改进都无法修复它。

这也不仅仅是关于可重复性。 如果您的构建依赖于一组特定的参数,而 _docker build_ 无法发现,那么您的自定义工具是世界上唯一可以构建它的构建工具:您无法再从假设的各种 CI/CD 工具和插件中受益一个原生的、可发现的 _docker build_。

@peterbraden在 #7115 中,一旦您添加了多个PUBLISH调用的功能,您现在可以生成多个图像。 然后您可以通过允许选择要构建的子图像来添加可配置性。 它们的关键是可配置性发生在 _Docker 可发现的子映像集中_。 这样你就可以保持可发现性。

@shykes > 一旦你的构建依赖于 Docker 上游的 3d 方工具
本身......您的构建的可重复性基本上为零。

我同意。 我认为我的大多数 Dockerfile 都依赖于 apt 和 apt 存储库
正在不断变化。 今天的构建与构建不同
昨天。 构建映像是唯一的黄金标准 imo。

如果可重复性不是限制的主要原因,CI 插件
支持似乎是一个非常弱的后备。 构建工具旨在
支持特殊用例。 一个插件,无非是
配置一个docker build cmd 似乎没什么用。 我的构建工具是
已经是脚本环境。 更糟糕的是,挖掘所有潜力
将用例加班到 Dockerfile 中似乎是一种糟糕的架构方式
它。 Dockerfile 应该专注于简单地通过
将图层添加到基本图像。 其他工作似乎不合时宜。

到目前为止,我喜欢 Docker。 很棒的工作家伙! 这个特殊问题刚刚发生
成为痛点。

2014 年 7 月 28 日星期一下午 12:25,Solomon Hykes通知@ github.com
写道:

@peterbraden https://github.com/peterbraden在 #7115
https://github.com/docker/docker/issues/7115 ,一旦你添加了能力
对于多个 PUBLISH 调用,您现在可以生成多个图像。 那么你
可以通过允许选择要构建的子图像来增加可配置性。
他们的关键是可配置性发生在
Docker_ 可发现的子图像。 这样你就可以保持可发现性。


直接回复此邮件或在 GitHub 上查看
https://github.com/docker/docker/issues/2112#issuecomment -50361586。

@thedeeno Dockerfile的目标是指定如何将源代码存储库转换为 Docker 可以运行的东西。

“_a_ Dockerfile 的目标是指定如何将源代码存储库转换为 Docker 可以运行的东西。”怎么样?

我认为我们可以同意,确实需要一种拥有多个 repo->image 映射的方法。 事实上,我们很多人都在滥用 shell 脚本和 makefile 来做到这一点。 根据我的经验,我还没有看到很多自定义命名的 Makefile - 配置和默认值是一股强大的力量。 正因为如此,我不相信人们滥用约定是一个现实的场景。

您建议的替代方法是在 Dockerfile 语法中添加一个关键字,这会使创建 Dockerfile 变得更加复杂。 我赞成保持这种语法尽可能简单。 与 Dockerfile 语法的其余部分相比,PUBLISH 等人似乎不够优雅。

还有遵循现有工具约定的想法。 正如已经提到的,-f 是一种常见的模式,人们在不知道它有效的情况下尝试它。 UI 应该是直观的,并且人们 _get_ -f 标志。 探索新的 Dockerfile 语法并不那么直观。

@peterbraden @shykes我同意 -f 更简单和直观。 我最初发现这个问题是因为我_期望_ Docker 已经有这个功能并在我开始为我们的应用程序测试它的第一天搜索它(大概是当它默认不起作用时)。

这不是边缘情况,除非您处于不测试软件或在多个环境中运行软件的情况。 过去 10 年我接触过的每个 repo 都要求能够在不同的上下文中运行。 我想这个线程上的很多人都有同样的问题。 我们都同意(我认为)约定对于您的应用程序的默认上下文显然是有价值的(假设您有一个)。

我通读了#7115(很快),不明白它是如何为我们解决这个问题的,也许这是 PR 上的文档问题,但如果难以沟通,它将导致 IMO 的挫败感和错误,而 -f 或一个类似的标志需要很少的努力来解释和正确使用。

使用 INCLUDE 想法创建了一个新提案 - https://github.com/docker/docker/issues/7277

作为旁注 - 考虑一个更有效的“APT”命令而不是笨拙的“RUN apt-get install -y ....”(然后是 YUM、EMERGE、PACMAN 和其他任何东西)可能是值得的

哦,考虑到很多人实际上只是尝试使用“-f”选项,如果每当您尝试使用它时,您会收到一条很好的错误消息,将您引导到描述新解决方案的文档中的页面,那将会很可爱。

我真的认为我们都忽略了房间里的大象。

@shykes说的是“事实上,你可以指向一个源代码目录,没有带外的其他信息,并完全按照上游开发人员的规范构建一个图像,这是非常强大的, Docker 的关键区别。”

我很确定这相当于说“在目录中键入docker build .绝对应该总是做正确的事情”,这相当于说“如果您的项目没有明显正确的docker build .去做,你错了”

我不能代表订阅这个问题的其他人的动机,但我自己对这个问题的动机正是docker build .没有明显行为的那些情况。 我想要调试版本还是发布版本? 我想要 postgres 内置还是应该发布单独的应用程序和 postgres 图像? 我是否希望它加载测试数据或生产数据? 我想运行测试吗?

当然,我希望生活在一个人们无需回答这些问题即可获得构建的世界中。 但我并不生活在那个世界。 当然,我可以随意选择这些问题的一些答案,并为docker build .定义行为。 但事实是,当用户键入docker build .时随意构建一些东西并不是“做正确的事”。

实际情况是,有些项目没有明显的正确可建项目。 在 docker 中有很多方法可以解决这个问题,比如-f支持,或者让用户从从其他地方导入的目标列表中进行选择,或者其他各种建议。 但它们都具有docker build .破坏的特性,设计使然。 这里有一个基本的阻抗不匹配,你不能只是提出解决它的方法。

每个项目都可以为docker build .选择明智的事情做的想法是一种幻想。 不可能做一些明智的事情的项目存在,而且数量众多。 目前唯一的问题是 Docker 是否会直接支持这些项目的多构建产品特性,或者它们是否会退回到传统的构建工具,如make甚至 shell 脚本。 现在正在发生这种情况:例如,较大的分布式 Docker 项目之一 Discourse,部分使用了本土构建系统来解决这个问题。

@drewcrawford你看,这正是问题所在。 “码头工人建造。” 应该构建_the_ 图像。 唯一真实的形象。 您应该更改 docker run 参数以将一个且唯一的图像的行为调整为不同的环境。
在这种情况下,您可能需要发布版本,只需要应用程序,别无其他。 所有其他的东西,比如“postgres 图像”是在运行时链接到你的应用程序的不同东西。 您可以使用相同的发布映像并使用非默认命令运行它以在其中执行测试。
理想情况下,借助多图像支持,您甚至不必在“发布”、“调试”和“带测试”构建之间进行选择——您只需拥有所有这些构建和 3 个小的差异构建。
如果你试图让 Docker 转向旧的思维方式,那你将度过一段糟糕的时光。 不要试图用螺丝刀锤击螺丝。

@algarius我认为问题在于这种想法不适用于实际应用程序,如果我们真的应该在这里进行范式转变,没有人解释它会如何。

允许多个图像是支持大多数现实世界网络可访问应用程序(具有不同依赖关系的多个环境)的需求的最简单和直观的方式。 为了解决这个可取的问题,是否以一种无法沟通的方式使语法变得更加复杂? 最后,您只是重新设计并混淆了这样一个事实,即您拥有 > 1 个具有不同依赖项的环境,这些环境可以很容易地以简单的方式表达,例如多个 Dockerfile,几乎不需要向软件的最终用户解释。

@drewcrawford提供了一个具体的例子,说明如何在当前现实世界流行的应用程序中处理这个问题,该应用程序由 Docker 支持分发。 他们应该怎么做?

@aigarius并不是说我不了解“码头工人的方式”。 我只是觉得不对。

例如,测试可能需要不同的构建——对上帝诚实_recompile_——因为必须有条件地编译某些对生产来说太慢的日志代码。

如果这听起来像是一个 make 系统的工作,那你是对的——这实际上是像我这样的人所做的,他们找到了使用实际构建系统编写 docker 构建脚本的方法。

这里的问题是 Dockerfile 不能既是构建的首选用户界面,也不能比make强大得多。 它可以是构建的首选用户界面,具有类似的功能,也可以是一个低级工具,以make等作为真正的用户界面。 但是“真正的”构建系统并不是任意复杂的——它们之所以复杂是因为人们使用了这些特性,而且没有多少简化的 docker 构建会改变这一点。 所有将发生的是 docker 将成为新的cc ,人们用make调用。

@shykes @drewcrawford @aigarius我已经写了一个简单的 -f 选项的提案,其方式与@shykes前面在此线程中描述的方式相同:#7284

@drewcrawford你是对的,要成为构建的首选用户界面, docker build确实需要至少与例如一样强大。 make 。 有两种方法可以做到这一点:

  • 1) 我们可以尝试重新实现 make 的每个变体的每个功能,以及在那里制作的每个替代品:Maven、scons、rake,当然还有很好的旧 shell 脚本。

或者

  • 2)我们可以认识到这些构建工具本身就是可执行程序,这意味着它们具有运行时依赖项,并且它们本身是从构建依赖项构建的——等等。 我们可以为您提供一种方法来_实际使用_您最喜欢的构建工具。 所以我们不需要重新实现 make 因为我们实际上可以构建和运行 make。

当您说make ,您指的是哪种口味的 make? 哪个版本? 究竟是从哪个 svn checkout 构建的? 使用哪些构建选项? 它链接到哪个 libc? 您也提到了cc相同问题。 也许这并不重要——也许你的应用程序最终会完全相同,无论我最终使用它来构建哪个随机版本的make 。 但同样,也许这确实很重要。 也许我获得与您完全相同的构建的唯一方法是使用与您使用的完全相同的 Make 和 Cc 构建。 今天没有简单的方法可以做到这一点——但这就是我想做的。

我真的不认为docker build是一种构建工具,确切地说 - 更像是一种元构建工具:一个已知的起点,您可以从中可靠地重建任何构建环境。 这就是#7115 的动机。

@shykes我认为没有必要真正从 make、Maven、rake 等中复制 _every_ 功能。毕竟,这些工具不会复制彼此的每个功能,而且它们以某种方式相处。

然而,Dockerfile 成为一种比目前更具表现力的语言是必要的(如果 Docker 是构建镜像的首选用户界面)。

这个问题的提议实际上是沿着这条路线的一个适度的举动:它说“我们需要一个与 make 的 _targets_ 等效的东西”。 “什么版本的 make”的问题并没有真正进入画面——“目标”的概念在 make、Maven、rake 和其他所有严肃的构建系统中都很常见。 它们有不同的语法,但特性本身是通用的这一事实应该表明这是人们在构建事物时经常做的事情。

他们正在构建的东西是 C 程序、Docker 镜像还是介于两者之间的任何东西都没有关系——您仍在构建某个目标。 构建目标的想法非常基本,它涵盖了构建系统实现、编程语言和操作系统。 我们在这里不是在谈论复制一些晦涩的 GNU Make 特定功能,而是在谈论具有最广泛协议的东西。

您试图在这里引入“元构建工具”的一些概念,但没有这样的东西。 就像 docker 可以编排 make 构建一样,make 也可以编排 docker 构建,事实上,现在正在以这种方式使用 make,因为无法为 Docker 指定构建目标。 但无论如何,这两个系统本质上都比另一个系统或多或少,它们都只是构建系统,构建目标,但在 Docker 的情况下,你只允许一个,这就是问题所在。

像#7115 这样的提议很有趣,但除非我遗漏了某些东西,否则它们不能有效替代目标。 目标告诉您要构建什么。 #7115 为您提供了一个更灵活的 DSL,它仍然只能构建一件事。 这是一些东西,但这不是这里所要求的。

docker build -t my_project_builder .
# Builds the builder container
docker run my_project_builder my_target | docker build -t my_project/my_target -< Dockerfile_MyTarget
# target is built, tarballed, and sent to stdout, then piped into a new docker build as the context and custom Dockerfile name

@drewcrawford只是为了确认,如果make clean; make foo , 2) 默认构建 _all_ 目标,并且 3) 有一种方法可以枚举目标......你会满意吗?

那将是令人满意的......我宁愿默认为开发人员选择的目标,而不是默认为所有目标,但我会接受任一解决方案

没关系。

@shykes @drewcrawford :+1:

所有将发生的事情就是 docker 将成为人们使用 make 调用的新 cc。

在这个问题上的提议实际上是沿着这条路线的一个温和的举动:它说“我们需要一个等价于 make 的目标”。 “什么版本的 make”的问题并没有真正进入画面——“目标”的概念在 make、Maven、rake 和其他所有严肃的构建系统中都很常见。 它们有不同的语法,但特性本身是通用的这一事实应该表明这是人们在构建事物时经常做的事情。

@drewcrawford :+1:+1,000,000

这是我一直遇到的情况:

我想从我的 repo 构建两个 Docker 容器。 也许一个是服务器,一个是数据库。 或者,一个是服务器,另一个是通过 API 调用对服务器运行自动化测试的客户端。

无论如何,我需要为这两个容器添加存储库中的一些文件。 按原样,如果不诉诸于在 bash 脚本中一次复制一个单独的 Dockerfile,进行构建,然后替换或删除 Dockerfile,就不可能做到这一点。

我需要:

  1. -f 命令指定要用作 Dockerfile 的文件。
  2. 添加文件而不是 Dockerfile 路径的能力。

既然一再说第一是不行的,我认为第二在技术上更难,那么“正确”的方法是什么?

@肖恩米洛

@shykes最后的评论似乎表明这不再像以前那样令人反感,但我认为我们仍然不清楚哪些现有提案是合适的,或者如果没有的话需要改变什么。

@jakehow感谢您的更新。 所以看起来这个问题的官方解决方案还很遥远。 与此同时,是否有“好方法”来做到这一点? 我最好的想法是一个 bash 脚本,它一次将一个文件复制到 repo 根目录中的“Dockerfile”并构建图像。 它会起作用,但感觉很脏。

@ShawnMilo是的,我认为大多数人都在使用构建工具(make、rake 等)或只是简单的旧 bash 脚本来执行此操作。

上面有人展示了一个片段,他们有一个构建器图像来处理这个问题。

这是我处理这个问题的方法。 我必须为平台的不同版本构建一个映像,比如 v2 和 v3。 所以我有一个 Dockerfile.v2 和一个 Dockerfile.v3 当我想做一个构建时,我先运行ln -s ./Dockerfile.v3 ./Dockerfile然后docker build .实际上我有一个脚本,我只运行./build v3./build v2

虽然我目前正在使用将指定的 Dockerfile 链接到./Dockerfile的脚本,但这将是一个不错的功能。

我创建了一个 PR #7995 来尝试解决这个问题。 在这个(长 :-) )线程中讨论的一些解决方案对于人们使用来说似乎非常痛苦。 Docker(对我而言)最大的卖点之一是它的易用性,因此要求人们跳过这些看似简单的问题并不合适。

现在,我可能遗漏了一些东西,但是为什么必须将其命名为“Dockerfile”有技术原因吗? 在创建 PR 时,我找不到 PR,而且我对它的更改如此容易感到惊喜。

@duglin你得到了我所有的支持。

这就是我们为解决当前项目中缺少-f选项而采取的措施。

# build.sh
...
mv specialDockerfile Dockerfile
docker build -t $(PROJECT) .

将此视为 +1 添加-f

目前我也在管理像 kikito 这样的东西。 我编写了几个 shell 脚本来从相同的上下文构建不同的图像,但很想看到一种方法来从 CLI 参数中指定一个 docker 文件,正如已经建议的那样。 +1 此请求。

+1000

我今天在尝试使用 docker 构建跨平台的 golang 项目时遇到了这个问题。 这有效,请参阅boot2docker ,但我需要一个 Makefile 将docker cp将 docker 内部的工件添加到我的构建目录。

但是,如果我尝试在我的 repo 的子目录中使用它,我的GOPATH就会损坏,因为 repo 根目录中的 .git 文件夹丢失了。 我需要ADD库根目录,然后在我的子目录中构建,但 docker 不允许这样做。

在阅读了这个长线程后,我看到了一个关于无法重现构建的担忧。 可以减轻这种情况的一种方法是仅允许-f选项指向构建上下文内或向下。 通过这种方式,您可以在子目录中拥有多个 Dockerfile,并从 repo 根目录构建它们。 此外,您可以将其限制在 repo 边界内,例如与 .git/.hg/.foo 和以下级别相同,但不在 repo 之外。

这就是我的想法

FROM scratch
BUILD myname1 path/to/dockerfile/in/context
BUILD myname2 path/to/dockerfile2/in/context
docker build -t myimage .

这将产生 3 个图像:

  1. 名为“myimage”的主图像,为了举例,其中没有任何内容
  2. 名为 myimage-myname1 的图像
  3. 一个名为 myimage-myname2 的图像

BUILD关键字将采用名称和指向 Dockerfile 的路径。 此 Dockerfile 必须在原始上下文中。
每个构建指令都可以访问主构建的完整上下文。
尽管将上下文限制为包含 Dockerfile 的目录树可能是值得的。

-1

对于这种特殊情况,您可以像dockerfeed一样使用上下文馈送器来docker build -

@itsafire重点是将这种类型的功能带入 Docker,以便这可以成为构建项目的一种受支持的方式。 我相信人们也会喜欢它与自动化构建一起工作。

我在这里不知所措。 我们对这个附加功能有几个拉取请求,对吗? 而且看起来并不难做到......甚至可以强制执行@maxnordlund提到的规则:将路径限制为相对于上下文/根。 这至少会使其与 boot2docket 等一起工作更顺畅,并使其“便携”。

这是迄今为止 Docker 中最令人恼火的差距,随着越来越多的工具开始使用 Docker 作为其功能的一部分,我们必须快速添加“-f”标志的功能,以便这些工具准备好在变得过于最终之前... 此外,众所周知,使用“-”并不能与这些工具一起使用,并且会严重限制功能。

有权威人士可以解释为什么这个修复程序还没有合并,或者至少为什么这个极度缺乏的功能仍然不存在?

开始感觉像暮光之城。

我想在 Docker 团队如何使用 Docker / 希望使用 Docker 以及社区的很大一部分如何使用 Docker 方面存在不匹配。 如果我错了纠正我。

docker 团队希望构建一个与 Debian 项目的存储库不太一样的软件存储库。 人们可以在这里获得自己喜欢的软件并轻松运行。 软件的构建过程应该是可重复且显而易见的。

其他人希望自动化他们现有的内部软件部署,这可能已经非常复杂,有很多构建工具、CI 系统等。对他们来说,Docker 只是另一个必须适合他们的基础设施的工具。 他们在如何使用 Docker 方面需要更多的灵活性。

我认为Docker(如.deb)可以满足双方的需求,但必须做出妥协。

基本问题是:这到哪里结束? Dockerfile 的图灵完整性? 可能不是。 总是需要更大的灵活性来解决特殊情况。 有些想法会进入 Dockerfile 语言,有些则不会。 由于 docker 能够在构建时通过 stdin 获取上下文,因此可以通过预处理器实现缺失的功能。

@itsafire上次我检查时, Dockerfile但不能吃上下文。 实际上,当您以这种方式提供 Dockerfile 时,上下文会被忽略。 如果他们增加了对您建议的支持,这将是一个封闭的问题。

我已经有一段时间没有看过了,但基本的要求是:给我们一种明确的方式来在构建过程中同时提供Dockerfilecontext 。 老实说,这就像 8 个月后仍然开放。

@thedeeno这确实是可能的
cat mystuff.tar.gz | docker build -

@cpuguy83但我无法使用该命令提供显式 Dockerfile。 对?

@thedeeno是的,你可以使用任何你想要的上下文来压缩你想要的任何 Dockerfile。

@cpuguy83 @thedeeno不,这不起作用,因为您无法添加任何文件,因为没有任何文件在您通常使用 Dockerfile 获得的“cwd”范围内。

编辑:这个说法是错误的; 我误解了@cpuguy83的例子。

@ShawnMilo是的。 tar 中的任何内容都在上下文中。

@cpuguy83对不起,我的错误。 我匆忙地将它读为 Dockerfile 中的管道,而不是整个 tarball。

@cpuguy83不错! 如果它像你建议的那样工作,我投票关闭。

附带问题,在我的自定义解决方案中,去皮时时间戳破坏了缓存。 那还是个问题? 如果我多次 tar 同一个文件夹,它会在构建时使用缓存吗?

继续伟大的工作!

管道整个上下文并不能减轻我们上面讨论的内容。

我们想要和需要的是一种将 _same_ 上下文与各种 Dockerfile 一起使用的方法。 例如前面提到的“带日志构建”和“不带日志构建”,作为单独的图像。 我还有很多其他需要这样做的用例。

我看不出对目录进行 tar-balling 对此有何帮助。 是的,可以创建一个特殊目录并将特定的 Dockerfile 复制到那里,然后复制整个上下文目录,或者 tar 并附加一个新的 Dockerfile,然后进行 gzip 压缩。 但是,这比我们目前必须采用的 [非常糟糕] 解决方法更容易,即在运行 docker 之前让预处理器脚本将正确的 Dockerfile 放置到位?

而且,正如我上面提到的,这对 Docker 生态没有帮助。

我错过了什么吗?

同样,一个简单的“-f”选项。 请。 拜托,漂亮拜托。 强制它是上下文的相对路径。 那没关系。

@davber您真正想要的是 Docker 为您处理上下文和 Dockerfile 的压缩包。
我并不完全反对这一点。 虽然我认为嵌套构建可能是一个更好的解决方案。

@cpuguy83 :是的,所以我希望 Docker 为我处理这个问题,是的,这将包括从一个地方选择上下文部分,从另一个地方选择 Dockerfile,或者使用非标准名称。 即,支持单独的“-f”标志:-)

嵌套构建不能解决我们面临的问题,它开始了这个线程,并继续下去。

即,我们仍然希望使用相同的根上下文。

是的,我们可以复制文件,并且,是的,我们这样做是为了避免这种奇怪的上下文与名为“Dockerfile”的确切 Dockerfile 的耦合。 但这并不理想,并且设置 rsync 以确保文件确实与原始文件相同很奇怪。

@cpuguy83 :你能解释一下嵌套构建如何帮助我,或者这里的任何其他“抱怨者”吗? :-)

@davber
我的看法是这样的:

FROM scratch
BUILD myname1 path/to/dockerfile
BUILD myname2 path/to/another/dockerfile

和这个:

docker build -t myimage .

将产生 3 个图像,“myimage”、“myimage-myname1”、“myimage-myname2”。
每个内部构建都可以作为绝对路径访问完整的构建上下文。 相对路径将相对于 Dockerfile。
并且“myimage”可以拥有它自己的东西,而不仅仅是 BUILD 指令。

正如我之前提到的,更大(和很棒!)Docker 生态中的许多新工具都假设每个 Dockerfile 都与一个 Docker 镜像相关联。 那里有各种类似“Fig”的协调器工具。 而很多特定支持Docker的新老云解决方案也有这种一对一的假设。 诚然,他们将在由 '-f' 选项创建的世界中,不仅必须获得上下文——例如作为焦油球——而且还必须获得一个可能独立的 Dockerfile。 但是每个这样的上传仍然只对应一个 Docker 镜像。

如果我们采用可能将 Dockerfile 与上下文根分离的方法,我希望这些工具将开始适应这种情况:

Each deployment/use of a Docker image is done with an upload of either:

   1. a Dockerfile solely, when no contextual operations are needed
   2. a context tar ball only, containing the context with a top-level Dockerfile
   3. both a context tar ball and a separate Dockerfile

我们在上下文的顶层使用这种“Dockerfile”的强耦合的时间越长,它在生态中就越根深蒂固。 即,我们应该现在就行动,因为 Docker 世界由于普遍令人敬畏而迅速发展。

而且,老实说,这是一个合理且在概念上有吸引力的假设,即在 Dockerfiles 和图像之间具有同构性,即使前者严格地是上下文目录 (tared up...) 和 Dockerfiles 的产品空间,默认为 (null, file) 如果只提供了 Dockerfile 并且 (context, context/'Dockerfile') 如果只提供了上下文。

甚至对于本地部署:假设我们至少要使用 Fig 进行本地编排:人们将如何做到这一点? 人们必须做的是从这样一个多构建的 Dockerfile 预先创建图像,然后参考图中的那些图像。 不是最优的。

Dockerfiles 和图像之间的同构

这个假设已经在这个线程中的人们如何使用 Dockerfiles 中被打破了。 即在执行 docker build 之前使用脚本手动替换 Dockerfile。 他们可能也有自己的编排。 此功能请求不是要改变 docker 格局,而是要让 docker 为特定用途而工作。

@hanikesn :两条评论:

  1. 为什么在构建之前必须将 Dockerfiles 复制到位会破坏这个假设? 它仍然是一个 Dockerfile <-> 一个图像?
  2. 我的论点是,我希望我们在这里提出的任何解决方案都能与现有和不断增长的 Docker 环境一起工作,而无需在此环境中进行太大的改变; 我认为通过_保持_提到的同构,我们这样做了。

这里的其他建议是拥有一个多映像 Dockerfile,可能会调用子 Dockerfile。 这不适用于大多数工具(图等)目前使用 Docker 的方式。

@davber

嵌套构建不能解决我们面临的问题,它开始了这个线程,并继续下去。

我提出了我之前已经指出的这个解决方案:

$ docker-pre-processor [ --options ... ] . | docker build -

--options是(此处)当前目录中的上下文将被更改并传递给 docker 的规则。 这必须通过创建一个包含上下文的临时 tar 存档来即时完成。 这样源上下文就可以保持不变。 更改预处理器比 Dockerfile 语法更容易。

@itsafire

今天期待 Dockerfiles 的工具呢? 他们变得越来越丰富,使用亚马逊、谷歌等。 和Fig和类似的编排框架。

然后,我们必须将标准化的“docker-pre-processor”工具以及此类工具的使用推向这些框架、提供者和工具。

至少有 'docker' 适当支持触发此线程的选项肯定会容易得多。

@itsafire解决了这个问题的每个人都已经在 docker build 周围使用某种预处理器或包装器来实现这个目标。

围绕这种情况的碎片化与@docker团队声明的“可重复性”目标相冲突。 这个讨论和其他讨论都是关于解决这个问题的。

1 年多和 130 多条评论以及影响大多数用户的一个简单问题……我印象深刻。 继续努力,Docker!

+1

工具应该帮助人们遵循自己的方式,而不是强加“正确”的方式。 一个让我参与讨论的简单案例:

`-- project
     |-- deploy
     |    |-- .dockerignore
     |    |-- Dockerfile
     |    ...
     `-- src

我的方法是保持项目根目录清洁。 但是ADD ../src-f deploy/Dockerfile不起作用。 现在我在项目根目录中有Dockerfile.dockerignore ,但这对我来说很痛苦。

在我这边,我构建了一个脚本,该脚本准备一个包含所需文件的文件夹并执行标准命令行docker build -t my/image .因为我遇到了ADD忽略.dockerignore文件的问题ADD ...

+1 肯定希望能够在单个存储库中拥有多个 Dockerfile。 我的用例:一个图像用于生产使用和部署,另一个图像是一个报告实例,旨在使用相同的后端工具和数据库连接,但不需要前端、Web、系统服务或流程监督......

+1 为此。 我需要为不同的服务器将文件添加到同一文件夹中的不同图像。

+1 到目前为止,我很喜欢 Docker,但由于我的团队设置的方式,我真的需要一种方法来构建不同的可部署程序,这些程序共享大量代码,来自一个 repo。 不是特别热衷于将它们全部构建到 uberdocker 容器中,因为它们的部署/发布周期不必要地捆绑在一起。 解决这个问题的最佳做法是什么?

@jfgreen :将多个 Dockerfile 放置在您喜欢的任何位置,并随意命名它们。 然后有一个 bash 脚本,将它们一次一个复制到 repo 根目录,作为“./Dockerfile”,运行“docker build”,然后删除它们。 这就是我为多个项目所做的,而且效果很好。 我有一个“dockerfiles”文件夹,其中包含名为数据库、基础、测试等内容的文件,这些文件都是 Dockerfile。

@ShawnMilo谢谢,这似乎是一个非常合理的解决方法。

+1

+1

+1 到-f 。 有一个合理的默认值,如果省略标志,Docker 将做_正确的事情。_ 在这种情况下,无论出于何种原因,_正确的事情_ 的非常具体的视图是针对用户的_错误的事情_ 有-f 。 以上与make等工具的比较我认为是合理的。 make也是一个非常固执的实用程序,最初编写于 1976 年,因此它有合理的时间来稳定功能集。 我认为在man make中,在非常简短的概要中唯一提到的标志是... -f

       make [ -f makefile ] [ options ] ... [ targets ] ...

固执己见、以用户体验为中心的实用程序没有问题,但像-f这样的东西是对用户生活的现实世界的务实点头。一个工具应该让你的生活更轻松而不是更难。 如果我必须编写Makefile或 shell 脚本来解决没有-f的工具,那是该工具的失败。 很明显,从花时间发表评论并给予 +1 权重的用户数量来看,即使在最初提出该功能一年后,该功能也具有显着的实用性。

+1

+1(或带有推荐解决方法的官方博客文章)

+1

+1

@crosbymichael我相信由于 #9707 被合并,现在可以关闭

胜利。

如果你们都想尝试这个新功能,你可以下载 master 的二进制文件:

master.dockerproject.com

谢谢@duglin

:拍:

谢谢@crosbymichael的二进制文件! :+1:

做的好各位! :拍:

所以它是docker build -f Dockerfile.dev . ? 编辑:是的

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