Moby: 重置从父图像继承的属性

创建于 2014-01-06  ·  153评论  ·  资料来源: moby/moby

在构建图像时,我可能想要重置其某些属性,而不是从父图像继承它们。 默认情况下继承所有属性是有意义的,但是应该有一种方法可以在有意义的时候显式和有选择地重置它们。

这是#2210 的更通用的解决方案,它只解决expose

arebuilder kinenhancement statuneeds-attention

最有用的评论

我绝对希望有某种方法可以删除从父图像继承的 VOLUME 点。

例如,假设我有一个应用程序的主映像,该应用程序使用外部挂载点存储持久数据,但我还想要一个基于它的映像,该映像已预先填充了测试数据。 按原样,如果父映像使用 VOLUME,我就不能这样做,因为对这些目录的任何更改/添加,即使这些更改是在 docker 构建期间,也会在提交时丢失。

所有153条评论

欢迎对语法提出建议。

我能想到的最好的是相应的命令,如UNVOLUME或更一般的-VOLUME (但这会增加更多的混乱,甚至可能造成+VOLUME应该工作的误解,并且应该与VOLUME )。

我绝对想要这样的东西(尤其是对于 VOLUME)。 VOLUME 之类的东西适用于 RUN 行,但 ENTRYPOINT 之类的东西则不然,这也有点令人迷惑。 有时这非常有用,有时则不然,但是通用的“禁用先前的 X 指令”可以很好地解决围绕该问题的问题。

在此期间是否有解决方法? 我正在使用 ENTRYPOINT (https://github.com/jagregory/pandoc-docker/blob/master/Dockerfile) 扩展图像,我需要取消设置入口点。 我尝试在我的 Dockerfile 中使用以下内容:

FROM jagregory/pandoc
ENTRYPOINT [] # this basically gets ignored (bug?)

FROM jagregory/pandoc
ENTRYPOINT [""] # this will make docker try to exec '' (the empty string)

FROM jagregory/pandoc
ENTRYPOINT ["/bin/sh", "-c"] 
# this will only work if docker run args are quoted:
#   docker run dergachev/pandoc "echo a b c"

谢谢!

我绝对希望有某种方法可以删除从父图像继承的 VOLUME 点。

例如,假设我有一个应用程序的主映像,该应用程序使用外部挂载点存储持久数据,但我还想要一个基于它的映像,该映像已预先填充了测试数据。 按原样,如果父映像使用 VOLUME,我就不能这样做,因为对这些目录的任何更改/添加,即使这些更改是在 docker 构建期间,也会在提交时丢失。

只是从@dergachev的评论中更新, CMD []ENTRYPOINT []上次我最近测试它们时正在工作,并且应该仍然有效(其他任何事情都可以用于提交错误)。

您可以通过以下方式重置所有单选项命令

ENTRYPOINT []
CMD []
USER 0
WORKDIR /

这应该将剩余的、不可重置的元数据保留为ENVVOLUMEEXPOSEONBUILD

(这是来自#8709)

如果我在父级中暴露了套接字 9000-9002,但需要在子级中取消暴露 9001,那么我必须以“取消设置”的风格编写

暴露
曝光 9000
曝光 9002

这会起作用,但是

未曝光 9001

看起来更好看。

一个优点是,它不会影响继承链更上游的任何 EXPOSE,我可能想稍后添加。

+1 @ codeon-nat

这已在 #8177 中讨论过,由于缺乏现实世界的用例,我们正在关闭它。

为什么要关闭这个? 有 9 人在这里发表评论。 我认为这将是一个非常有用的东西。 现实世界的用例能够轻松地基于现有图像进行构建。 有时您想添加属性,有时您想删除它。 这是正常的。

我同意,例如,我正在为 SSL 卸载程序扩展nginx图像,我想要UNEXPOSE 80但保留443

如果您想运行多个实例,例如 nginx,能够不公开端口是非常重要的。

没关系,这对我来说只是糟糕的配置。

(4 月 15 日:“没有真实世界的用例”我很惊讶你无法想象至少一个并关闭了这个)

我有一个基础映像,它为可选软件公开卷或端口,然后在另一个 Dockerfile 中创建一个不应公开任何它不想公开的内容的映像,甚至不应公开已从祖先中卸载的内容。 为什么我们不希望能够删除这些设置?

我也有一个用例。 我希望能够创建一个包含数据库快照的图像,但所有 mysql 包都设置了VOLUME /var/lib/mysql 。 如果能够关闭在我的 Dockerfile 中对数据库所做的更改将与图像保持一致的卷,那就太好了。

唯一的其他选择是完全重新创建自定义 mysql 映像,但这在某种程度上似乎很浪费,因为很多其他人已经组装了比我更好的默认 mysql 服务器。

添加一个额外的用例 - 我继承了官方的RabbitMQ 镜像,但我只想公开 websocket 端口(80 和 443)而不是默认的 AMQP 端口(5672)。 看起来这应该是一件非常合理的事情?

添加另一个用例。 我想使用 gogs 图像构建一个 git 测试环境,但是让数据持久化很乏味,因为它全部存储在一个卷中。 如果我能够在设置环境后简单地取消音量并构建我的图像,那就太好了。

+1

继承自官方php,想用sockets代替端口所以需要去掉暴露的9000端口

任何以非平凡能力使用过 Docker 的人都会发现这些继承容器的局限性。

@shykes @icecrime现在如何关闭? 使用当前的语法和向后兼容性的需求是否太难解决? 计划是什么?

+1 - EXPOSE 覆盖的真实用例在这里。

考虑到这种情况已经持续了 3 年多(发现问题可以追溯到 2013 年),我们什么时候才能删除暴露的端口?

+1。 需要能够“UNEXPOSE”默认 nginx 端口 80 和 443。

对于这里要求UNEXPOSEEXPOSE语句只提示容器暴露了哪些端口,但实际上并没有_暴露_这些端口; 您需要_发布_这些端口( -p / -P )以在主机上公开它们。 换句话说; 从 Dockerfile 中省略EXPOSE语句确实对图像有_no_ 直接影响(您仍然可以,例如到达容器的“端口 80”)。

此外,如果您想公开其他端口,只需让容器中的服务在这些端口上运行,这将起作用。

是的,但是如果使用 -P(公开所有端口)并且您的基本图像公开了一个您不再想公开的端口,那么您就被卡住了。 您需要切换到使用 -p 并列出所有其他端口。

@thaJeztah很高兴知道。 然而,添加 UNEXPOSE 有什么害处? 这对我也很有用,即使那只是为了拥有更好的文档化容器。

@kgx没有害处(除了可能的功能膨胀),但想解释一下无法“公开”不是安全问题(有些人有这种印象)。 UNVOLUME (或UNSET VOLUME )仍然在我的个人愿望清单上。 :-)

我很高兴我在尝试 docker 的前 72 小时遇到了这个问题。 我使用的具有任何类型继承的任何其他主要工具的每个配置或语言都具有“覆盖父级”类型的功能。

这是一个用例:我正在使用 go-ethereum 的默认 docker 映像,并且我需要能够设置一个绝对不会连接到外部世界的测试版本。 我确实需要能够从主机和其他容器连接到它。 最安全的方法是更改​​端口,因为程序会急切地尝试连接到对等点。 我还需要能够覆盖 CMD 和 ENTRYPOINT 来制作我运行一次的图像的“设置数据库”版本,以创建正确的卷。 所有这些都很难在 Dockerfile 中实现。

您可以将其分配给另一个 IP 地址...或绑定不同的主机端口。 稍后关于过度使用入口点和 cmd 只是重新定义它们。

---从拳击手发送| http://getboxer.com

2月20日2016年8点57分零零秒GMT,barkthins [email protected]写道:在这里, “SA使用案例:我使用的是默认的泊坞窗图像细末复仇,我需要能够建立一个测试绝对不会与外界连接的版本。 我确实需要能够从主机和其他容器连接到它。 最安全的方法是更改​​端口,因为程序会急切地尝试连接到对等点。 我还需要能够覆盖 CMD 和 ENTRYPOINT 来制作我运行一次的图像的“设置数据库”版本,以创建正确的卷。 所有这些都很难在 Dockerfile 中实现。 —直接回复此邮件或在 GitHub 上查看。

CMDENTRYPOINT可以在运行时被覆盖; docker run --entrypoint=foo myimage mycmd 。 这里的问题是在测试期间使用不同的图像和不同的入口点/cmd 是否有用,因为您不会_testing_ 将在生产中运行的实际图像。 (只是一个旁注)

从这些回复看来,dockerfile 似乎已被弃用,以支持命令行选项,至少就入口点、cmd、expose 而言,可能还有其他一些选项。 命令行已经做了 Dockerfile 不能做的事情,所以这似乎是方向。 如果这是意图,那么我将尽可能多地将 Dockerfile 信息移至实例化时间,以减少混淆。 这是意图吗?

@barkthins不, CMDENTRYPOINT 。 我的例子是为了表明在某些情况下(例如在您的图像上运行替代命令),您可以在运行时覆盖它们。

从 Dockerfile 手册页:

     -- EXPOSE <port> [<port>...]
     The EXPOSE instruction informs Docker that the container listens


运行时指定的网络端口。 Docker 使用这些信息来
使用链接和 _to 设置端口互连容器
在主机上重定向_

  • 系统。*
    [...]
    历史
    * 2014 年 5 月,由 Zac Dover (zdover at redhat dot com) 编译,基于
    在 docker.com 上的 Dockerfile 文档。 *2015 年 2 月,由 Brian Goff 更新(
    [email protected]
    可读性 * 2015 年 9 月,由 Sally O'Malley 更新(
    [email protected]

[我的斜体] 如果你说的是
真的。

2016 年 1 月 28 日星期四上午 6:43,Sebastiaan van Stijn <
[email protected]> 写道:

对于这里要求 UNEXPOSE 的人; 仅 EXPOSE 语句
给出容器暴露的端口的_提示_,但不
实际上_暴露_这些端口; 您需要_发布_这些端口(-p / -P)
将它们暴露在主机上。 换句话说; 省略 EXPOSE 语句
来自 Dockerfile 确实对图像有 _no_ 直接影响(您可以
仍然,例如到达容器的“端口 80”)。

此外,如果您想公开其他端口,只需将
容器中的服务在这些端口上运行,这将起作用。


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

目前正在合着一本关于 Docker 的书:使用代码 39miell 获得 39% 的折扣
http://manning.com/miell/?a_aid=zwischenzugs&a_bid=e0d48f62

thaJeztah 我的观点和我认为这个线程的观点是继承不一致。 是的,您可以覆盖 ENTRYPOINT 和 CMD,但 EXPOSE 会增加曝光度,除了在命令行上之外,您无法替换父级的曝光度。 我还没有检查其他命令以查看是否存在第三种行为。 也没有记录哪些命令扩展或替换了父命令。

@thaJeztah我们需要 UNEXPOSE

有几种解决方案可以读取容器元数据并提供额外的上游配置。 例如; 使用 HAPROXY 我必须设置EXCLUDE_PORTS=8080以阻止它尝试动态提供对我的 Tomcat 应用程序上该端口的访问。

开发人员查看暴露的端口并对容器的行为做出假设。 例如,我有一个扩展 Tomcat (EXPOSE 8080) 的基本映像,但该映像使用与默认端口不同的端口 (EXPOSE 8888)。 如果您在复合图像中添加 Web 服务器(例如,运行 NGINX 和 Tomcat),您将通过 HTTP(EXPOSE 80 和 EXPOSE 443)提供内容。

在后一个示例中,您最终会得到一个图像,该图像自我记录为暴露 8080、8888、80 和 443,其中只有 80/443 是相关的。

尽管有非常具体的文档,但我必须不断向社区中的开发人员解释事情,这一事​​实证明了这些都是真正的问题; 当您只需查看图像时,谁需要文档? <--当图像自我记录错误时的每个人。

此问题有解决方法,但它们是解决方法。 这是一个主要的架构问题吗? 为什么 Docker 不能考虑一个更优雅的解决方案来解决这个实际问题。

这方面的状况如何?

@BillBrower状态是他们关闭了问题,但没有提供他们认为这不是问题的理由。 显然,对于我们中的许多人来说,它仍然是困扰我们日常生活的现实世界问题;)

@modius @BillBrower即使它已关闭,也可以随时重新考虑; 基本上“不是暂时的”,但在合并/实现功能时“是永远”,因此如果对功能有顾虑,维护者的正确选择是说“不”。

实现此功能的 PR 已关闭,因为维护人员不确定该功能,并正在寻找更多实际示例以供使用; https://github.com/docker/docker/pull/8177#issuecomment -93587164

由于我们大多不同意,因此我们将关闭此问题,但请随时在评论中证明我们是错误的,我们可以重新考虑

那是一年多前的事了,所以事情可能已经改变了; 我将重新打开这个问题,并将在下一次维护者会议中提出这个问题。 (请注意,由于 DockerCon 和即将发布的 1.12 版本,这可能比平时稍长)

谢谢,@thaJeztah。 这很有意义。 感谢您解释最初决定背后的基本原理,并概述如果我们希望这种情况发生,您需要了解什么。

_UNVOLUME_ 请求的一个用例

特别是因为目前,当您使用自定义卷驱动程序时,它适用于给定容器的所有卷。

我有一个 EFS 卷驱动程序的情况:当我在启动时指定卷绑定时工作正常。 如果我没有设置任何绑定,它会失败,因为它尝试从自动生成的 UUID 挂载 NFS 共享。 这意味着我必须为我的所有卷提供绑定,即使是我不关心的卷,例如由父映像创建的卷。

现在唯一的解决方法是在启动时将我不需要的所有卷绑定到同一 EFS 共享的垃圾空子文件夹。

注意:我不能使用 docker volume 命令,因为所有这些都是由 Marathon 启动的,并且应该可以在单个 docker run 命令中使用。

+1 UNEXPOSE 需要

+1 表示未曝光

+1 表示未曝光

+1 表示未曝光

+100 为 UNEXPOSE

+9000 为 UNEXPOSE

+∞
例如,我使用官方存储库 nginx (FROM nginx:stable) ,它包含在 Dockerfile 中:

EXPOSE 80 443

但我想移到另一层,即端口 80。例如:

UNEXPOSE 80

请!
添加此功能!!!!

@frekele ,如果我是你的母亲或父亲,你就不会得到。 没门。

不曝光 +++
非常必要的功能!

拜托,您不需要用电子邮件通知向其他人发送垃圾邮件,而且您绝对不需要用所有这些“+1”评论来扰乱讨论。 你可以对问题描述用👍来表达你的同意。

@underyx这是
请参阅https://github.com/isaacs/github/issues/9#issuecomment -195120703(整个线程很好,但这是 GH 添加反应的时间)。
现在让我们不要把讨论弄乱;)
/offtopic

我们在维护者会议上讨论了这个问题,一般来说,我们可以再次开始处理这个问题。

@duglin您可能有兴趣从事此工作吗?

不知道我是否有时间,但只是总结一下....基于上述评论,我认为要求是确保人们可以清除/取消设置以下内容:

EXPOSE  (all or specific one)
ENV  (specific - not sure we need to clear all yet)
LABEL  (ditto)
VOLUME  (all or just specific paths? probably both)
CMD  (possible but only using the json format)
ENTRYPOINT  (possible with json format)

我错过了什么吗?

+10000 为 UNVOLUME

@duglin我认为从目前 _not_ 可能的那些开始,并且大多数请求将是最好的( EXPOSEVOLUME )。 我还没有看到对其他人的很多要求(但没有反对)。

最初的 PR 使用UNSET <SOMETHING> ,但后来改为UN<SOMETHING> 。 我个人更喜欢第一个(更通用),但@shykes更喜欢UN<SOMETHING> ,不确定是否已经改变。

UNVOLUME会很好。

我的用例:我正在使用mysql图像并希望将包含在/var/lib/mysql目录中的数据库提交到新图像,但不能,因为它在父 Dockerfile 中声明了一个卷。

@thaJeztah我发现UNSET <something>更容易阅读而不是那么奇怪; 无需开始发明单词。 编写脚本的人也很熟悉。 一个也可以做

UNSET  EXPOSE VOLUME LABEL

我的例子,

我正在设置 dokuwiki 安装。 我选择的图像暴露了所有潜在的配置卷。 我想做的是从这个基本映像自定义我的安装。 由于卷被暴露,我无法在图像构建时修改 PHP 配置文件。

我可以将基本图像修改为 UNVOLUME 这些卷,但随后我将需要永远保持该图像......使用“最新”的魔力消失了:(

+1 为 UNEXPOSE :)

+1 表示 UNVOLUME 或更好的 UNSET VOLUME。

+1 为 UNVOLUME。 这对我现在可能有用。 在大学场景中也可能很有用,在这种情况下,学生无需担心必须安装卷即可启动。

无需担心必须安装卷。

我认为不需要它; Dockerfile 中的VOLUME定义会根据图像中该位置的内容自动创建一个“匿名”卷。

@duglin ,你已经在做这个了吗? 如果没有,我会接受它并从最需要的(音量和暴露)开始。 让我知道。

@runco​​m去吧 - 还没有找到时间。

作为提醒,请注意UNENV命令仍然很有用,可以有选择地取消设置环境变量(例如,同时匹配UNVOLUME d 的卷)。 未设置的变量与设置为空白的变量不同,尤其是在 shell 中与set -ue一起使用时。

可以从官方图片中删除 VOLUME 和 EXPOSE,如果
他们是一个问题。

2017 年 1 月 28 日 21:23,“henryptung”通知@github.com 写道:

作为提醒,请注意 UNENV 命令仍然有用,
有选择地取消设置环境变量(例如,匹配
同时取消音量的音量)。 未设置的变量不是
与设置为空白的变量相同,尤其是与 set -ue in 一起使用时
壳。


您收到此消息是因为您订阅了此线程。
直接回复本邮件,在GitHub上查看
https://github.com/docker/docker/issues/3465#issuecomment-275875623或静音
线程
https://github.com/notifications/unsubscribe-auth/AAdcPAKP1tii706MY-8MxVPSFLTFme8Dks5rW7HggaJpZM4BXt2-
.

+1 为 UNVOLUME

+1 为 UNVOLUME

我的 UNVOLUME 用例:

在将网站源复制到 /var/www/html 的 S2I 场景中使用 library/worpress 图像

VOLUME 通过在生成的图像上安装一个空的 FS 来压缩它。 -> 库/wordpress 不能使用。

@groulot实际上,如果您没有使用--volume显式挂载卷,则映像的内容将在创建容器时复制到卷中。

docker run 命令使用基础映像中指定位置存在的任何数据初始化新创建的卷。

https://docs.docker.com/engine/reference/builder/#/volume

有一个使用 docker save/load 的 hacky workarround,参见http://stackoverflow.com/q/42316614/808723

+1 为 UNVOLUME

我想回应@modius能够 UN-EXPOSE 的理由。 开发人员在学习 docker 时首先要考虑的事情之一是输入docker ps以查看他们的容器发生了什么。 他们会看到标准端口被列为可用。 开发人员习惯于从他们在 Docker 之前的世界中设置的本地或测试环境中的事物的标准端口,因此引入 Docker 很困难,因为他们看到标准端口并认为它会起作用——但实际上他们是未连接到 docker 容器。

+1 表示 UNVOLUME、UNEXPOSE、UNENV、...

这个好像开了好久了。 这里有什么牵引力吗?
我还想使用官方的 PHP fpm alpine 映像和 UNIX 套接字而不是 TCP 端口 9000。
无法覆盖来自父级的 EXPOSE,并且宁愿不构建该图像只是为了摆脱 EXPOSE。

+1

+1

希望能够取消设置 VOLUME 命令。 Wordpress 官方图像将其完整的代码库强行转储到一个卷中——我更喜欢只有 wp-content/uploads 目录的卷,以便代码库的其余部分可以烘焙到图像中。

将镜像部署到 kubernetes 集群时限制了 root 访问 VOLUME 目录无法访问,解决方案是覆盖父镜像中定义的卷

来自我的 +1

UNEXPOSE 的用例

假设我有四个 docker 主机,我想运行 16 个 maven tomcat 容器,它们都默认为内部端口 8080。

现在想象一下,我正在使用带有 Rancher CNI 的注册器 - 这将我锁定到内部端口。
https://github.com/gliderlabs/registrator/issues/541#issuecomment -305012416
这意味着我只能在每台主机上运行一个 8080 内部端口。 (因为我必须做 8080:8080 端口映射)

在这种情况下 - docker 的内部-> 外部端口映射不足以解决我的问题。 我实际上需要覆盖内部端口映射,最好不要重建原始容器。

朱利安,我不知道你是如何进行 1 对 1 映射的。 对我来说,注册人为
与路由流量无关,它只是注册和取消注册
运行容器。 例如,我以一种注册器将维护的方式使用它
通过将 Docker 分配的 IP 和暴露的端口放入 Etcd 实例
那里。 然后使用 confd 它将监视一个 Etcd 实例并更新 nginx
在自己的容器中配置。
2017 年 6 月 17 日星期六 04:06,Julian Gamble通知@github.com
写道:

UNEXPOSE 的用例

假设我有四个 docker 主机,我想运行 16 个 maven tomcat
所有默认为内部端口 8080 的容器。

现在想象一下我正在使用带有 Rancher CNI 的注册器 - 这将我锁定
到内部端口。
gliderlabs/registrator#541(评论)
https://github.com/gliderlabs/registrator/issues/541#issuecomment-305012416
这意味着我只能在每台主机上运行一个 8080 内部端口。 (因为我有
做 8080:8080 端口映射)

在这种情况下 - docker 的内部-> 外部端口映射是不够的
解决我的问题。 我实际上需要覆盖内部端口映射,
最好不要重建原始容器。


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/moby/moby/issues/3465#issuecomment-309189149或静音
线程
https://github.com/notifications/unsubscribe-auth/ABrq2QGgY81wbePOBKbkTSjpUSoPIocuks5sE0LCgaJpZM4BXt2-
.

嗨,布拉德利,

谢谢你看这个。 我将注册器与 Rancher 内置的 ipsecurity 结合使用。 正如您从此处的链接中看到的:
https://github.com/gliderlabs/registrator/issues/541#issuecomment -305012416
在牧场主计划的容器中查看注册器中的外部端口的能力受到限制。 这意味着您只能使用内部端口。

你可以看到有用户在寻找解决方案的焦虑:
https://forums.rancher.com/t/do-you-kill-registrator/5152

和这里提出的解决方案:
https://github.com/cabrinoob/rancher-registrator
(这对某些人来说是不可行的)。

如果您在谷歌搜索“注册牧场主”,您可能会找到更多信息。

他们建议您以“内部”模式运行注册器 - 您可以将内部端口 1:1 映射到外部端口。 这导致了UNEXPOSE - 很快就会耗尽内部端口。

我的观点是,用于主机内 docker 容器网络的 ipsecurity 可能导致您被锁定到以 1:1 映射到 docker 中的外部端口的内部端口的用例。 为此,您需要有一个UNEXPOSE命令。

谢谢你看这个。

干杯
朱利安

3.5年过去了,这个问题没有进展?...

+10086 用于 UNEXPOSE。 有时父镜像可能不是官方的,它使用非官方的端口,我们应该有能力覆盖端口。

@pumba-lt
我敢打赌,这没有解决的原因是,他们不知道如何在技术上做到这一点。

当有明确的解决方法时,它还增加了 Dockerfile 语言的复杂性。 不要在父 Dockerfile 中推送太多配置,而是为继承的图像保留 if。 (又名:停止在 docker hub 上获取随机图像:D)

从 docker 17.05 开始,还有一种进行多阶段构建的新方法,可以消除对这个问题的大部分需求(这是一个Dockerfile ):

# First import the original image
FROM nginx AS source-image

# Second step of the build, start with an empty image
FROM scratch
# Copy the data from the original image
COPY --from=source-image / /
# Re-define all the config
EXPOSE 80
STOPSIGNAL SIGTERM
CMD ["nginx", "-g", "daemon off;"]

编辑:忘了说,第二个解决方案压缩了所有以前的层。 我认为这没什么大不了的,但很高兴知道。

@zimbatm - 太棒了!

我敢打赌,这没有解决的原因是,他们不知道如何在技术上做到这一点。

变化本身并不太复杂; 可以在这个 PR 中找到一个实现; https://github.com/moby/moby/pull/8177。 当时没有达成共识,但如果你关注我 1 月份的评论; https://github.com/moby/moby/issues/3465#issuecomment -247405438,事情发生了变化(除非人们从那时起改变了主意),我们会接受贡献来实现这一点。

至于为什么它还没有; 仅仅是因为没有人有时间开始研究它,但如果有人感兴趣,它很可能会被接受。

@zimbatm是的,您的示例将解决直接问题,请注意它还会创建一个不同的图层,并将所有图像图层展平。 尽管这在某些情况下可能会减小图像大小,但也会导致这些图层不再与使用nginx作为父级的图像共享,因此可能导致需要下载更多图像。 例如;

原始 nginx 镜像:

$ docker inspect nginx -f '{{json .RootFS.Layers}}' | jq .

[
  "sha256:54522c622682789028c72c5ba0b081d42a962b406cbc1eb35f3175c646ebf4dc",
  "sha256:1c3fae42c5007fd0e70309b5b964eb5d49046562bd425424da734784098894e7",
  "sha256:87823f21b7939eac6e099fa878871a806c1904a7698793edb63bf6e5f5371e1f"
]

以及你创建的 nginx 镜像;

$ docker inspect nginx2 -f '{{json .RootFS.Layers}}' | jq .
[
  "sha256:9a71ba430225d4f24e0d57837a71b6b2b68bf88ca7530c0a89c98783c98531b5"
]

感谢更新@thaJeztah

我可以重复我的建议使用吗

UNSET XXXX

而不是发明新的和奇怪的词汇(例如:UNVOLUME)。

我们也可以这样在一行中取消设置多个属性。

UNSET VOLUME EXPOSE LABEL

我个人认为UNSET做一个或另一个可能不会有太大的变化,所以当 PR 到来时我会把它留给审查过程

嗨,即使第二次使用FROM ,我如何保留父映像中的所有内容,但不公开父 docker 映像中公开的某些端口? 对此是否有任何官方解决方案,让我们接受并继续工作或拒绝

让我们要么接受这一点,要么继续努力,要么拒绝

@rajiff看到我上面的评论https://github.com/moby/moby/issues/3465#issuecomment -313549657 欢迎贡献

变化本身并不太复杂; 可以在这个 PR 中找到一个实现; 第8177章当时没有达成共识,但如果你关注我一月份的评论; #3465(评论),事情发生了变化(除非人们从那时起改变了主意),我们会接受贡献来实现这一点。

因此,如果共识可能已经改变,为什么不重新打开#8177呢?

因此,如果共识可能已经改变,为什么不重新打开#8177?

那个 PR 是在三年多前打开的; 该代码不再适用

不必专门使用 UNsomething 命令,
为什么不改进 FROM 命令并使其能够列出我们实际想要继承的内容呢?

我们可以使用类似的东西:
从基础图像(音量,暴露,端口,..)
或者如果你真的想要否定它:
FROM baseimage (*, -VOLUME, -EXPOSE)
或者有更好的语法;)

在我看来,所有这些首先应该是 FROM 命令的一部分。

从 Dockerfile 中更改卷:如果任何构建步骤在声明卷后更改了卷中的数据,则这些更改将被丢弃。

这似乎并不完全正确。 你仍然可以这样做:

VOLUME /avolume/subdir
WORKDIR /avolume
COPY ./Dockerfile /avolume/subdir

我不知道它是否可以用于撤消卷。

覆盖父映像/容器 ENTRYPOINT 在最新版本中不起作用。

17.09.1-ce版本

$ docker run --name=experiment --entrypoint=/bin/bash ubuntu:16.04
$ docker inspect experiment --format "{{.Config.Entrypoint}}"
[/bin/bash]
$ IMAGE=$(docker commit -c "ENTRYPOINT []" experiment)
$ docker inspect $IMAGE --format "{{.Config.Entrypoint}}"
[]

17.10.0-ce版本开始

$ docker run --name=experiment --entrypoint=/bin/bash ubuntu:16.04
$ docker inspect experiment --format "{{.Config.Entrypoint}}"
[/bin/bash]
$ IMAGE=$(docker commit -c "ENTRYPOINT []" experiment)
$ docker inspect $IMAGE --format "{{.Config.Entrypoint}}"
[/bin/bash]

UNSET ENTRYPOINT也不起作用。
是bug吗?

@alexey-igrychev 你能为此单独开一个问题吗? 您正在评论的问题是在 Dockerfile 中实现UNSET xx指令的 _feature request_。 ( UNSET指令尚未实现,所以这是预期的。)

作为该问题的解决方法,使用[""]而不是[]作为入口点似乎有效;

IMAGE=$(docker commit -c "ENTRYPOINT [\"\"]" experiment)
docker inspect $IMAGE --format "{{.Config.Entrypoint}}"
[]

我还需要一种取消设置音量的方法,以便我可以创建一个预先加载了表和数据的数据库图像。
不幸的是,基础映像是私有的(oracle),因此我什至无法复制基础 dockerfile,因为我无权访问它。 我只能扩展图像。
这个问题列出了大量的 +1 和现实世界的用例,并且已经为它制作了多个 PR,但 PR 已经关闭。 那么我们需要做什么才能获得这个功能呢?

@veqryn自重新打开此问题以来,没有人开始处理拉取请求; 现有的拉取请求不再完全适用于代码库,因此必须打开一个新的拉取请求; 如果有人对此感兴趣,那么事情可以重新开始。

见我之前的评论; https://github.com/moby/moby/issues/3465#issuecomment -247405438

我们在维护者会议上讨论了这个问题,一般来说,我们可以再次开始处理这个问题。

@duglin您可能有兴趣从事此工作吗?

https://github.com/moby/moby/issues/3465#issuecomment -313549657

至于为什么它还没有; 仅仅是因为没有人有时间开始研究它,但如果有人感兴趣,它很可能会被接受。

我的用例来自 docker-compose.yaml:我想要一个用于开发的撰写文件,其中包含用于添加 TLS 反向代理、Maven 存储库、接管 80/443 端口、不公开端口 80 和 5432 的生产覆盖开发撰写文件公开。 或用于生产的撰写文件与开发覆盖。

从 Dockerfiles 继承的分层组合文件的仅添加性质使系统设计复杂化。 如果可以撤消某些参数,或者如果我只是使用覆盖激活构建了不同的容器,那将非常酷。 我并不挑剔它在 docker-compose 引擎盖下的工作方式。

谢谢@thaJeztah - 您能否将我们指出在您看来是开始阅读以通过拉取请求修复此问题的地方的代码行?

我自己对构建器代码的工作不多,但更改应该在https://github.com/moby/moby/tree/master/builder包中。

这个问题有3年了! 就一个如此基本的功能达成一致是否如此困难,还是我错过了什么?

@caruccio是的,你错过了一些东西:向上滚动 4 条评论https://github.com/moby/moby/issues/3465#issuecomment -356988520

我还有几个用例(一个是个人项目,第二个是工作项目),我希望在其中重载VOLUMEEXPOSEENTRYPOINT语句父图像。

虽然我有ENTRYPOINT的解决方法,只需使用ENTRYPOINT []设置一个新的空入口点,并且可能会学会忽略EXPOSE ,......我仍然在抓挠我对如何不继承VOLUME定义的想法。

我刚刚在我的代码库中遇到了这个问题,其中父图像有一个 VOLUME,这意味着我在子图像中对这个体积的所有更改都被丢弃了。 我以为我疯了 2 天,直到我终于找到了解决这个问题的方法。 请有人可以实现这一点。

有一个变通办法。

您始终可以docker save image -o image.tar ,解压缩该存档,编辑元数据并重新打包docker load -i image2.tar 。 这样就可以制作一个没有任何先前 VOLUME 声明的 image2 。

由于我必须定期执行这些步骤,因此我创建了一个小脚本来帮助清理第三方图像。 看看docker-copyedit

很棒的工作

@gdraheim哇,太棒了! 从自述文件:

删除所有卷的愿望来自这样一个事实,即我确实想下载一个经过测试的图像进行本地测试,其中数据部分也应该提交到历史记录中,以便将程序和数据都恢复到定义的状态,以便另一个测试运行将从完全相同的检查点开始。

这也是我们的用例。

我已经扩展了 docker-copyedit 以涵盖图像的所有元数据条目,因此它可以处理所有继承的属性,甚至超出 EXPOSE 和 VOLUME 列表的问题情况。 那将是经常看到的东西的用户、工作目录、标签、环境设置。 将 ENTRYPOINT 复制到 CMD 也是我经常做的修改。 无需再进行中间的 docker-build 步骤,只需执行docker-copyedit 即可。 ;)

Docker 团队用于跟踪并反复忽略这个问题的时间可能足以解决它。

在显然有大量用户要求此之后,我们现在可以重新打开它吗?
或者至少给出一个合理的论据来反对它,而不仅仅是忽略所有用例(我也想取消暴露一个端口,只是为了获得更干净的 docker ps 输出而不用他妈的(80/80/tcp)因为我会建立自己的形象.. ..(这对于非开源 Dockerfiles 来说更难)

问题仍然悬而未决; 它是开源的; 欢迎贡献https://github.com/moby/moby/issues/3465#issuecomment -356988520

我认为这会在moby/buildkit 中修复吗? 我在那里看到了大部分Dockerfile 命令基础设施。

我也是UNSET的粉丝,比如

UNSET EXPOSE 9000

或者

UNSET LABEL foo

所以,我正在查看具有子命令形式的命令,比如HEALTHCHECK CMD形式,我注意到HEALTHCHECK已经有一个未设置的形式......

HEALTHCHECK NONE

这是一个有趣的选择,但是HEALTHCHECK也只定义了 1 个配置(并覆盖了最新的配置),它不允许定义多个,例如LABELEXPOSE ,和VOLUME做。

我只是想知道这些应该如何交互,或者是否有其他类型的NONE形式可能有效。

在使用主机网络时,确实需要一些删除暴露端口的方法来控制暴露的内容。

+1 暴露 []

所以.... Docker 团队 5 年来无法实现 UNSET 操作符,太棒了

正如@AnthonyMastrean所说,我们应该将此问题移至moby/buildkit项目吗?

还有一个 PR,有很好的文档记录和测试,但没有合并,我们也应该移动/重新调整这个 PR 吗?

此功能将非常受欢迎并解决 Azure 中基于 nginx 的图像的问题。

UNSETCLEARRESETOVERRIDEIGNORE就可以了 - 我会避免UNxxx因为那样'd 复制保留密钥列表以支持和记录。

使用FROM时也可以指定忽略/重置的内容,例如

FROM nginx:1.13 IGNORE EXPOSE, ENTRYPOINT

我建议另一种解决方法,使用多阶段构建。
它将所有文件从原始图像复制到新图像,但没有元数据。

FROM postgres as orig

FROM alpine:3.8 as postgres
COPY --from=orig / /
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 5432
CMD ["postgres"]

我不敢相信我没有想到这一点。 这实际上非常好@kotofos。 你失去了上游容器的层,但这并不是一个巨大的损失。

@kotofos为什么不是FROM scratch as postgres

@farcaller好收获。 从头开始肯定会更好,因为您要覆盖整个文件系统

最后我测试了它, COPY --from=xxx ...不会保留文件系统
所有权,因此您可能要小心使用该解决方法。

@tianon你是对的,但对于单进程容器这应该不是问题,因为你可以使用--chown标志来设置你在容器中执行的用户

https://docs.docker.com/engine/reference/builder/#copy

这可以追溯到 2014 年。 已经 5 年了,似乎在不久的将来所有属性都不会出现通用的“未设置”或“重置”。 我也喜欢通用的方法,但有很多事情需要考虑,而且真的:它不会很快发生。

那么:我们能否至少获得一个“UNEXPOSE”来关闭所有那些打开的端口,或者至少获得与 CMD 和 ENTRYPOINT 相同的行为(最后一个获胜)? 考虑到来自其他命令的“最后一个获胜”行为,这是最需要的“未设置”属性,并且对于不知道(非直观)行为的用户来说,这是一个潜在的安全风险。

我建议另一种解决方法,使用多阶段构建。
它将所有文件从原始图像复制到新图像,但没有元数据。

FROM postgres as orig

FROM alpine:3.8 as postgres
COPY --from=orig / /
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 5432
CMD ["postgres"]

我想忽略PGDATA指向的 docker 卷,这样我就可以将其内容与图像捆绑在一起,而不是作为卷。
对我来说更轻松的解决方案是简单地更改PGDATA

FROM postgres:11.2-alpine
ENV PGDATA /var/lib/postgresql/test-data

# stuff that will create all my schemas
COPY create-scripts /docker-entrypoint-initdb.d/

# a weird way to trigger the entrypoint script to run the stuff in docker-entrypoint-initdb.d but not hang after starting postgres
RUN /docker-entrypoint.sh postgres --version

在 dockerfiles 中使用EXPOSEVOLUME有什么好处吗? 毕竟,您可以在docker run (和docker-compose文件)中轻松定义它们,使用--expose (或-p )和命名卷或绑定安装。 我不止一次因为它们而被咬,并且没有办法重置它们(创建新的 dockerfile 不太可行,特别是在扩展官方图像或使用 makefile 创建的图像时)。 我认为它们是一种反模式,我认为弃用它们会更好。

@lucasbasquerotto EXPOSE 被诸如 gitlab-runner 之类的工具用于检测由图像声明的端口是否实际打开。 我同意这应该更多是检测容器是否准备好的健康检查职责,但是拥有声明的端口列表对于自动化确实很有用。
需要 VOLUME 来提供停止/启动容器的用户友好体验,并使数据自动持久化。 同样,我认为这可以通过其他方式解决,但是让数据可检查对工具有好处(在这种情况下对人类也是如此)。

ps 不是在为 Dockerfile 语法辩护,我只是指出反模式不是由关键字本身引起的,而是因为生态系统没有向前发展以解决常见用例(例如这个用例)中可能出现的问题,或者例如提供带有声明卷和卷中的一些起始数据的图像(例如具有预加载架构的 mysql 图像)

@zarelit我不知道gitlab-runner究竟是如何工作的,但我认为应该有一种方法可以指定要在 Dockerfile 之外检查的端口(我发现了一个可能是由于这个问题,因为 MySQL 公开2 个端口,但它应该只检查端口 3306:https://gitlab.com/gitlab-org/gitlab-runner/issues/4143)。 据我所知,它也只使用了最后一个 Dockerfile 的暴露端口。

关于VOLUME ,您可以使用命名卷保留有状态数据或使用-v将其挂载到现有目录(如果您想在重新创建容器时保留数据)。 我也认为使用这种方法会更好,因为 dockerfile 中的VOLUME对于扩展该 dockerfile 的人来说有点晦涩,如果您不知道它在那里,您可能会认为您的容器是可复制的在不同的环境中,并且您可以在没有副作用的情况下更改版本,但稍后会被咬,因为它在后台使用持久数据。

它也不允许您在构建期间将文件移动到该目录(假设您不想将其用作卷,但它继承了将目录定义为卷的 Dockerfile,例如定义/var/www/html/ wordpress /var/www/html/作为一个 VOLUME,我需要使用一些技巧来使用另一个目录)。

使用-v您可以明确声明您想要该卷,并避免由于 Dockerfile 中VOLUME的黑魔法而导致的意外意外。

此外,它最终可能会创建大量匿名卷:

在镜像内定义一个卷会告诉 docker 将此数据与容器的其余部分分开存储,即使您在启动容器时没有定义卷。 Docker 存储这些数据的方式是创建一个没有名称的本地卷。 名称本身是一个很长的唯一 id 字符串,不包含对它所附加到的图像或容器的引用。 除非您在删除容器时明确告诉 docker 删除卷,否则这些卷将保留,不太可能再次使用

来源: https :

@lucasbasquerotto我基本同意你的看法,所有长期存在的问题都存在,我认为弃用应该遵循一条不会变得无效的路径,它们会变得像……建议的路径,您可以在卷中提交,服务器可以侦听的建议端口。

我认为 Docker 旅程的美好部分现在已经被提取到 OCI 标准中,因此我们应该编写新的工具,而不是肩负所有这些遗留问题。

对于任何觉得它有用的人,请随意使用tugboat.qa docker images 。 它们是几个官方 docker 镜像的扩展,删除了卷。 在这里完成繁重工作的 GitHub 存储库的记录最少: https :

在 dockerfiles 中使用EXPOSEVOLUME有什么好处吗? 毕竟,您可以在docker run (和docker-compose文件)中轻松定义它们,使用--expose (或-p )和命名卷或绑定安装。 我不止一次因为它们而被咬,并且没有办法重置它们(创建新的 dockerfile 不太可行,特别是在扩展官方图像或使用 makefile 创建的图像时)。 我认为它们是一种反模式,我认为弃用它们会更好。

现在许多供应商将他们的应用程序作为一个简单的容器映像提供,并随同提供 dockerfiles。
在这些文件中包含EXPOSEVOLUME可以使用简单的应用程序,在应用程序目录中使用简单的docker run 。 您无需了解应用程序期望的参数,它适用于 dockerfile 中提供的所有默认值。
所以是的:虽然我们有更好的、更大的枪,比如 compose 或 k8s,用于简单的复杂应用程序,但本地应用程序 dockerfiles 仍然非常适合。 并且具有正常工作的默认值使使用方便。

@m451较短的

您可以轻松地运行docker run --expose 3000 -v my_volume:/container/dir some_image而不是docker run some_image并且清楚地了解暴露给主机的端口和即使在容器被销毁后仍将保留的卷。

此外,这是一件微不足道的事情,只有在需要时才公开和映射卷(也许您不需要 dockerfile 中公开的所有端口,也不需要定义所有卷。如果公开某些端口真的很重要或者使用一些卷,最好将它记录在存储库中,这样人们不仅知道需要公开或映射的内容,而且为什么,毕竟这是会影响容器外部的东西,并且可能会在之后持续存在容器被破坏)。

如果它在 dockerfile 中,当一个卷被持久化而你不知道(特别是如果一个 dockerfile 是从另一个继承的,你可能不知道)事先定义一个体积,除非你更深入地检查它的作用)。 所以即使这个问题解决了,我也会认为 VOLUME 和 EXPOSE 不好。

此外,虽然这个问题没有解决(我不知道需要多少年才能解决,考虑到它已经开放了 5 年半以上),但我根本没有办法重置他们

在 dockerfiles 中使用EXPOSEVOLUME有什么好处吗? 毕竟,您可以在docker run (和docker-compose文件)中轻松定义它们,使用--expose (或-p )和命名卷或绑定安装。 我不止一次因为它们而被咬,并且没有办法重置它们(创建新的 dockerfile 不太可行,特别是在扩展官方图像或使用 makefile 创建的图像时)。 我认为它们是一种反模式,我认为弃用它们会更好。

现在许多供应商将他们的应用程序作为一个简单的容器映像提供,并随同提供 dockerfiles。
在这些文件中包含EXPOSEVOLUME可以使用简单的应用程序,在应用程序目录中使用简单的docker run 。 您无需了解应用程序期望的参数,它适用于 dockerfile 中提供的所有默认值。
所以是的:虽然我们有更好的、更大的枪,比如 compose 或 k8s,用于简单的复杂应用程序,但本地应用程序 dockerfiles 仍然非常适合。 并且具有正常工作的默认值使使用方便。

我认为这样做的供应商是出于无知而这样做的。 不了解这会给想要在生产环境中使用他们的产品的人带来什么问题。 当然,它使某人更容易建立产品的测试/演示实例。 但是现在,如果我想真正运行它,我必须 git clone/sed 他们的 Dockerfile 或创建自己的 Dockerfile 才能获得一个工作映像。

@m451较短的

您可以轻松地运行docker run --expose 3000 -v my_volume:/container/dir some_image而不是docker run some_image并且清楚地了解暴露给主机的端口和即使在容器被销毁后仍将保留的卷。

此外,这是一件微不足道的事情,只有在需要时才公开和映射卷(也许您不需要 dockerfile 中公开的所有端口,也不需要定义所有卷。如果公开某些端口真的很重要或者使用一些卷,最好将它记录在存储库中,这样人们不仅知道需要公开或映射的内容,而且为什么,毕竟这是会影响容器外部的东西,并且可能会在之后持续存在容器被破坏)。

如果它在 dockerfile 中,当一个卷被持久化而你不知道(特别是如果一个 dockerfile 是从另一个继承的,你可能不知道)事先定义一个体积,除非你更深入地检查它的作用)。 所以即使这个问题解决了,我也会认为 VOLUME 和 EXPOSE 不好。

此外,虽然这个问题没有解决(我不知道需要多少年才能解决,考虑到它已经开放了 5 年半以上),但我根本没有办法重置他们

同意。 因此,让我们定义一种标准方式来传达所需的参数。
如果没有,我们最终会遇到与遗留应用程序相同的混乱:供应商特定的文档和文档格式。 有些会告诉您要打开哪些端口,有些则不会。 有些只告诉你一半,有些告诉你错误的端口。 有些只告诉你端口号而不是协议等等。

Dockerfiles 是将这种混乱标准化的好方法。

@m451我同意你的观点,但最好考虑到仅仅公开端口并不能传达有用的信息。 暴露的端口需要什么样的数据/连接? 如果有多个端口,每个端口的作用是什么?

如果您想保留数据,您希望将其挂载到命名卷或主机上的某个位置,VOLUME 对此无济于事。 如果您希望以更高的性能存储临时数据,那么 VOLUME 会有所帮助(这是 VOLUME 可能有用的唯一情况)。 在容器中写入较慢,因为它使用写入时复制策略。 但同样,在 docker run 上映射卷也避免了 CoW(您不需要 VOLUME),唯一的缺点是您的指令更长,您需要知道路径(但这仅当您的性能下降时到牛)。

使用 VOLUME 和 EXPOSE 作为一种文档并不能证明不良(或缺乏)文档是正确的。 而且它也可能(并且可能会)伤害图像的某些消费者。

@m451我同意你的观点,但最好考虑到仅仅公开端口并不能传达有用的信息。 暴露的端口需要什么样的数据/连接? 如果有多个端口,每个端口的作用是什么?

正确的。 端口的洞想法从一秒。 观点已经过时。 然而:在这里,我们试图定义哪些端口需要打开,哪些端口可以保持关闭状态,并了解通过每个端口交换哪些数据。 HTTPS 已经成为今天几乎所有东西的包装器,除了代码的作者之外,通常没有人知道通过特定端口传输的数据到底是什么。 即便如此,它可能会随着每次更新而改变。

在 RL 中,除了最终对应用程序进行故障排除之外,您并不关心通过哪个端口传输哪些数据/信息。 您决定信任该应用程序。 因此,如果应用程序打开端口 X 和 Y,那么您也可以信任它。
对于标准的日常操作,最好启动一个应用程序,它开箱即用(假定为安全默认值)。
容器已成为打包应用程序的一种形式,可以让它们开箱即用。

也就是说,我同意好的文档很重要。 然而在 RL 中,没有人愿意花几个小时阅读文档只是为了知道要打开哪些端口。 它不会为日常操作任务带来任何好处。

我的那块馅饼。

在 Dockerfile 中使用VOLUME毫无价值。 如果用户需要持久性,他们将确保在运行指定容器时提供卷映射。 很难找到我无法设置目录所有权 (/var/lib/influxdb) 的问题是由于 InfluxDB 的 Dockerfile 中的 VOLUME 声明造成的。 如果没有UNVOLUME类型的选项,或者完全摆脱它,我将无法更改与指定文件夹相关的 _anything_。 这不太理想,尤其是当您有安全意识希望指定某个 UID 时,图像应该作为 运行,以避免随机用户在您的主机上运行软件。

在为用户自定义扩展图像时,应该有一种方法可以覆盖这些 VOLUME 指令。 我目前唯一的解决方案是自己完全重新创建图像,使整个 _Dockerfile FROM_ 动态无用。

nginx: 最新
部署到heroku后,nginx暴露了80端口,但heroku不允许,那我该怎么办? 从 nginx 复制所有 dockerfile 并删除 EXPOSE 80?

我不会写任何新的……但是覆盖 EXPOSE 指令会非常好。

分享这个 - https://github.com/gdraheim/docker-copyedit/blob/master/docker-copyedit.py (不是我的创作,要清楚,谢谢@gdraheim!)

这帮助我从使用命令在 dockerfile 中设置的 postgres 容器中删除了一个卷:

python docker-copyedit.py FROM postgres:11.5-alpine INTO postgres:11.5-alpine remove volume /var/lib/postgresql/data

似乎在没有损坏容器的情况下完成了工作,获取了原始图像,对其进行了调整,创建了一个没有卷的新图像(根据docker inspect在从调整后的图像创建的容器上运行),而不是将它用于任何其他用途,但 git README 允许进行各种操作,即

 ./docker-copyedit.py FROM image1 INTO image2 -vv \
     REMOVE PORT 4444
 ./docker-copyedit.py FROM image1 INTO image2 -vv \
     remove port ldap and rm port ldaps
 ./docker-copyedit.py FROM image1 INTO image2 -vv \
     remove all ports
 ./docker-copyedit.py FROM image1 INTO image2 -vv \
     add port ldap and add port ldaps

LABEL 是另一个“属性”(尚未提及),它可以使用“取消设置”功能

正如这篇 SO 帖子中提到的: https :

从上游图像重置/删除VOLUME另一个用例:

我正在扩展一个 oracle 数据库映像,但它在/opt/oracle/oradata上有一个卷。 在默认的 oracle 镜像中,数据库在容器启动时创建并写入该卷。 但这会导致容器首次启动需要 25 分钟,这是不可接受的。 所以我正在处理一个图像,其中数据库是在图像构建时创建的,但因此我需要删除VOLUME /opt/oracle/oradata我的数据库被创建但是当我启动容器时,文件系统/opt/oracle/oradata是空的再次,我的数据库无法启动。

我正在扩展一个 oracle 数据库映像,但它在/opt/oracle/oradata上有一个卷。

也正是我的用例。 我想生成一个预分配的可插拔数据库,其他人可以从我们的私有 docker 注册表中提取该数据库……但缺少该卷。 我将不得不深入挖掘并决定最不丑陋的解决方法。

我已经解决了如下:

我已经使用docker-copyedit删除了卷,然后我编写了一个 bash 脚本来创建数据库(您可以查看 oracle 的启动脚本以了解它是如何完成的)。 现在使用预配置的 PDB,从镜像启动容器只需 25 秒。 但是图像变得非常大。

更好的方法是扩展现有的 docker 规范以包含粘性环境变量/覆盖选项的概念,例如;

例如我基于上游 tomcat 图像的项目:

--ENV CATALINA_HOME /some/other/path
tomcat:8.5.54-jdk8-openjdk
...

在声明 ENV 的地方 - 它应该被提升到粘性状态并保持声明的值/覆盖稍后在处理 Dockerfile 链中为此变量遇到的任何值。

--ENV = 从 Dockerfile 中的这一点开始。

因此,如果您希望它优先于任何进一步遇到相同变量(例如在多阶段构建中),则可以在 Dockerfile 的开头使用它。 还可以根据它在 Dockerfile 中的位置提供灵活性,以便文件中更高的引用独立。

不需要 UNVOLUME,因为正确的方法是使用其他人可以覆盖的 ENV 引用声明 VOLUME。

例如

ENV PROJ_VOL /some/path
体积 $PROJ_VOL

看起来ENTRYPOINT []ENTRYPOINT [""]在不使用 BuildKit 时都会使每个构建的缓存无效。 简单的Dockerfile来演示:

FROM jrottenberg/ffmpeg:4.3-alpine311 as base

ENTRYPOINT []

RUN echo "HERE!"

第 2 步和第 3 步将_从不_使用缓存。 这是我的解决方法:

FROM jrottenberg/ffmpeg:4.3-alpine311 as base

ENTRYPOINT ["/usr/bin/env"]

RUN echo "HERE!"

我无法在你的第一个模式上重现缓存失败::confused:

$ cat Dockerfile
FROM alpine:3.12
ENTRYPOINT []
RUN echo 'HERE!'

$ docker build .
Sending build context to Docker daemon  17.25MB
Step 1/3 : FROM alpine:3.12
 ---> a24bb4013296
Step 2/3 : ENTRYPOINT []
 ---> Running in d921be2e563d
Removing intermediate container d921be2e563d
 ---> 7801c649d895
Step 3/3 : RUN echo 'HERE!'
 ---> Running in 9e2ca2cf1f9f
HERE!
Removing intermediate container 9e2ca2cf1f9f
 ---> d398fdd442b1
Successfully built d398fdd442b1

$ docker build .
Sending build context to Docker daemon  17.25MB
Step 1/3 : FROM alpine:3.12
 ---> a24bb4013296
Step 2/3 : ENTRYPOINT []
 ---> Using cache
 ---> 7801c649d895
Step 3/3 : RUN echo 'HERE!'
 ---> Using cache
 ---> d398fdd442b1
Successfully built d398fdd442b1

我认为您必须使用定义ENTRYPOINT 。 尝试使用我所做的图像或mysql

哦,有趣——我可以使用mysql:8.0进行复制。 固体错误! :+1:

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

相关问题

darklajid picture darklajid  ·  286评论

AaronFriel picture AaronFriel  ·  206评论

phemmer picture phemmer  ·  190评论

PanJ picture PanJ  ·  324评论

digital-wonderland picture digital-wonderland  ·  141评论