Dockerfile中的ONBUILD指令

79

我在Docker文档中读到了ONBUILD指令的使用方法,但是它并不清楚。
请问有人可以解释一下吗?


1
你不理解文档的哪一部分? 如果你正在构建一个将被用作基础来构建其他镜像的镜像,这将非常有用。 - Vaidas Lungis
但是我可以用它做什么呢?请给我一个例子。 - softshipper
1
文档中也包含示例。首先,您可以使用所需的操作系统库(如curl、gd等)创建自定义图像dockerfile,并添加onbuild指令以稍后添加源代码。例如 onbuild add src/然后,您可以创建另一个dockerfile,但使用先前创建的图像(FROM指令),并在其上堆叠源代码。因此,您将获得具有冻结操作系统级别库和源代码的图像。 - Vaidas Lungis
1
抱歉,我必须将其减一;这方面有很多例子。请参见http://container42.com/2014/02/06/docker-quicktip-3-onbuild/。 - Roy Truelove
3个回答

64

ONBUILD指令非常有用,可以自动化构建所选择的软件堆栈。

示例

Maven容器专为编译Java程序而设计。神奇的是,您的项目的Dockerfile只需要引用包含ONBUILD指令的基础容器即可:

FROM maven:3.3-jdk-8-onbuild
CMD ["java","-jar","/usr/src/app/target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]

基础镜像的Dockerfile说了一切:
FROM maven:3-jdk-8

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

ONBUILD ADD . /usr/src/app

ONBUILD RUN mvn install

有一个基础镜像,其中已经安装了Java和Maven,并有一系列的指令来复制文件和运行Maven。
下面的答案给出了一个Java示例:

“instruction” 有一个错别字,如果 StackOverflow 允许一字符编辑,我会进行修正而不打扰任何人。 - Wyck
ONBUILD 指令会在镜像中添加一个触发器指令,以便在稍后的时间执行。 - M. Rostami

29

根据docker文档的说明:

ONBUILD指令为镜像添加触发指令,以便在将镜像用作构建的基础时,在稍后的时间执行。 在下游Dockerfile中执行触发器,就好像它已立即插入到下游Dockerfile中的FROM指令后面的上下文中一样。

那么这是什么意思呢?让我们看一下这个Nodejs Dockerfile:

FROM node:0.12.6

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

ONBUILD COPY package.json /usr/src/app/
ONBUILD RUN npm install
ONBUILD COPY . /usr/src/app

CMD [ "npm", "start" ]
在你自己的Dockerfile中,当你输入FROM node:0.12.6-onbuild时,你会得到一个镜像,这意味着build命令已经运行过了,所以除了那些以ONBUILD开头的指令之外,所有其他指令都已经被执行了。这些指令会在另一个时间被执行,也就是当下游生成(当你的镜像从自己的Dockerfile构建时)使用此镜像作为基础(FROM node:0.12.6-onbuild)。

现在你不能只是调用ADDRUN,因为你还没有访问应用程序源代码,并且每个应用程序构建的源代码都不同。

没错!包含onbuild指令的镜像并没有在你的机器上构建,所以它还没有访问package.json的权限。
然后,在执行你自己的Dockerfile中的任何指令之前,构建器将查找ONBUILD触发器,这些触发器是在构建父镜像时添加到元数据中的。
这样可以省去你自己执行这些命令的麻烦,实际上这些命令就好像写在你的Dockerfile中一样。
最后,他们补充说:

你可以简单地提供一个样板Dockerfile给应用程序开发人员复制粘贴,但那样效率低下、容易出错并且难以更新,因为它与特定于应用程序的代码混在一起。

问题是如果这些指令在模板Dockerfile中被修改,那么你也必须在自己的Dockerfile中进行修改。但是由于ONBUILD指令,我们不需要担心这个问题。

0
没有任何答案或评论提供关于ONBUILD指令存在的原因的解释,所以我会在这里尝试提出自己的解释。请随意评论或编辑此答案以改进它。
ONBUILD似乎是为Dockerfile编写者提供方便,以消除复制源文件等样板代码。通过构建一个具有ONBUILD指令的镜像,这些指令将应用于从Dockerfile构建的镜像,而无需以任何方式引用它们,只需引用构建镜像的源镜像。
所有这些听起来都像是一种“神奇的酱料”,在我看来,人们应该仔细考虑是否希望将这种东西纳入自己的工作流程中。就个人而言,我不希望有ONBUILD的存在。ONBUILD的存在迫使我仔细研究任何我想要构建的源镜像的元数据,以防它们在我的构建中执行某种“神奇”的构建指令,我应该意识到这一点。我宁愿将这样的构建指令明确地包含在我的Dockerfile中,以确保可重现性和对应该发生的事情以及何时发生的确定性,更不用说诸如敏感数据泄露之类的安全风险了。
编辑:
幸运的是,有一种方法可以禁用ONBUILD指令:在构建镜像时使用“docker build --no-on-build”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接