softshipper
softshipper

Reputation: 34061

Dockerfile ONBUILD instruction

I read on the docker documentation how ONBUILD instruction can be used, but it is not clear at all.
Can someone please explain it to me?

Upvotes: 86

Views: 55215

Answers (3)

Mark O'Connor
Mark O'Connor

Reputation: 77941

The ONBUILD instruction is very useful for automating the build of your chosen software stack.

Example

The Maven container is designed to compile java programs. Magically all your project's Dockerfile needs to do is reference the base container containing the ONBUILD intructions:

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

The base image's Dockerfile tells all:

FROM maven:3-jdk-8

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

ONBUILD ADD . /usr/src/app

ONBUILD RUN mvn install

There's a base image that has both Java and Maven installed and a series of instructions to copy files and run Maven.

The following answer gives a Java example:

Upvotes: 67

ack
ack

Reputation: 7572

None of the answers or comments provide an explanation of the reason for the existence of the ONBUILD instruction, so I'l try to come up with my own here. Please feel free to comment or edit this answer to improve it.

ONBUILD seems to be meant as a convenience for Dockerfile writers to eliminate boilerplate such as copying source files etcetera. By building FROM an image which has ONBUILD instructions, these instructions get applied to the image being built from a Dockerfile without the need to reference them in any way other than the source image FROM which an image gets built.

All this sounds like a whole lot of 'magic sauce', and IMHO one should carefully consider whether one wants that kind of thing in ones workflow. Personally, I don't. The very existence of ONBUILD forces me to carefully study the metafata for any source images I would like to build from, in case they perform some kind of 'magic' build instructions in my own build which I should be aware of. I would rather explicitly include such build instructions into my own Dockerfiles, for the sake of reproducibility and certainty about what is supposed to happen and when, not to mention security risks such as exfiltration of sensitive data.

EDIT:

Luckily there is a way to disable ONBUILD instructions: use docker build --no-on-build when building an image

Upvotes: 2

jperl
jperl

Reputation: 5112

As stated by the docker docs:

The ONBUILD instruction adds to the image a trigger instruction to be executed at a later time, when the image is used as the base for another build. The trigger will be executed in the context of the downstream build, as if it had been inserted immediately after the FROM instruction in the downstream Dockerfile.

So what does that mean? Let's take this 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" ]

In your own Dockerfile, when you do FROM node:0.12.6-onbuild you're getting an image, which means the build command has already been run, so the instructions have ALREADY been executed as well, however all but those starting with ONBUILD. These have been deferred to another time, when the downstream build (when your image is getting built from your own Dockerfile) uses this image as the base (FROM node:0.12.6-onbuild).

You can’t just call ADD and RUN now, because you don’t yet have access to the application source code, and it will be different for each application build.

That's right! The image containing onbuild instructions wasn't built on your machine, so it doesn't yet have access to package.json.

Then when you build your own Dockerfile, before executing any instruction in your file, the builder will look for ONBUILD triggers, which were added to the metadata of the parent image when it was built.

That spares you the hassle of executing these commands yourself, it really is as though these commands were written in your own Dockerfile.

Finally, they add:

You could simply provide application developers with a boilerplate Dockerfile to copy-paste into their application, but that is inefficient, error-prone and difficult to update because it mixes with application-specific code.

The thing is that if these instructions are modified in the boilerplate Dockerfile, you will have to modify them as well in your Dockerfile. But thanks to the ONBUILD instruction, we don't have to worry about it.

Upvotes: 32

Related Questions