Pages

Friday, May 7, 2021

Understanding Docker ONBUILD Instruction

 

While Dockerfiles are executed in order from top to bottom, you can trigger an instruction to be executed at a later time when the image is used as the base for another image. The result is you can delay your execution to be dependent on the application which you're building

ONBUILD instruction works in a different way. This instruction will not run in this image but will set a trigger instruction to be executed at a later point. The Onbuild instruction in our example is “ONBUILD RUN mkdir /tmp/hello”. This instruction will not be executed in the current image but will be executed in the next image if the current build is used as Base image. Lets understand with an example,

In the First Dockerfile we have,

[root@ip-172-31-31-127 onbuild]# cat hello1/Dockerfile

FROM busybox

RUN echo "hello world" >> /tmp/hello

ONBUILD RUN mkdir /tmp/onbuild-hello

Now when i build the docker image hello1 with the above dockerfile as below,

[root@ip-172-31-31-127 hello1]# docker build -t hello1 .

Sending build context to Docker daemon  2.048kB

Step 1/3 : FROM busybox

latest: Pulling from library/busybox

53071b97a884: Already exists

Digest: sha256:4b6ad3a68d34da29bf7c8ccb5d355ba8b4babcad1f99798204e7abb43e54ee3d

Status: Downloaded newer image for busybox:latest

---> 64f5d945efcc

Step 2/3 : RUN echo "hello world" >> /tmp/hello

---> Running in cadcbc51c329

Removing intermediate container cadcbc51c329

---> c24d27271dee

Step 3/3 : ONBUILD RUN mkdir /tmp/onbuild-hello

---> Running in 827b86347475

Removing intermediate container 827b86347475

---> 1eae88c4a42d

Successfully built 1eae88c4a42d

Successfully tagged hello1:latest

Now if i run the image and see the contents of the container, we don’t see any directories created as defined in ONBUILD instruction

[root@ip-172-31-31-127 hello1]# docker run -it hello1 /bin/sh

/ # ll /tmp

/bin/sh: ll: not found

/ # ls /tmp

hello

/ # exit

Now lets see the second Dockerfile,

[root@ip-172-31-31-127 hello2]# cat Dockerfile

FROM hello1

RUN echo "second Build" >> /tmp/second

Now in the second dockerfile, iam using the hello1 ( created above ) as base image. Now if we create the image and run a container from it, we can see things as below,

[root@ip-172-31-31-127 hello2]# docker run -it hello2 /bin/sh

/ # ls /tmp

hello          onbuild-hello    second

We can see that the onbuild-hello directory is created in the container created from the image whose base image is hello1. Now in order for the ONBUILD instruction to execute, we need to create a container whose base image has this ONBUILD instruction.

 

In a production application, a nodejs application Dockerfile would look like below,

[root@ip-172-31-9-137 tmp]# cat Dockerfile

FROM node:7

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" ]


Build the image and name the image as node:7-build. The result is that we can build this image but the application specific commands won't be executed until the built image is used as a base image. They'll then be executed as part of the base image's build. In the above Dockerfile, the instructions that start with ONBUILD will not be executed in the node:7-build but when this image is used as base, they will be executed.


With all of the logic to copy the code, install our dependencies and launch our application the only aspect which needs to be defined on the application level is which port(s) to expose. The advantage of creating OnBuild images is that our Dockerfile is now much simpler and can be easily reused across multiple projects without having to re-run the same steps improving build times.


FROM node:7-onbuild EXPOSE 3000


Build the application as node-app and run the application,

docker run -d --name node-app -p 3000:3000 my-nodejs-app

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

No comments :

Post a Comment