/ DOCKER, INDUSTRIALIZATION, ONBUILD

ONBUILD, the overlooked Docker directive

It’s hard to ignore Docker nowadays. There are a lot of blog posts available on the Web. The problem is that most always repeat the same. In this post, I’d like to focus on one directive that I find overlooked via a use-case: it is Java specific, but the parallel can be easily drawn to other tech stacks.

The problem

The situation is the following: as a developer, I’d like to use Docker as a way to package a JAR from the sources of my application.

As a reminder, here’s a sample Maven structure:

|__ src
|     |__ main
|           |__ java
|                 |__ Application.java
|           |__ resources
|                 |__ application.properties
|__ pom.xml

With Docker, this is as easy as creating a Dockerfile that inherits from the Maven image:

Dockerfile
FROM maven:3.6.0-alpine   (1)

WORKDIR app               (2)
COPY . /app               (3)
RUN mvn package           (4)
1 Start from one of the official Maven image on Dockerhub
2 Set the working directory to app
3 Copy the current host directory to the image app folder
4 Build the JAR

This works as expected.

Now, let’s imagine I’d need to package several such apps. All Dockerfiles will follow the same structure as above. That contradicts the DRY principle.

The solution

Among the many directives available in the syntax of Dockerfiles is the ONBUILD one.

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.

— Docker documentation
https://docs.docker.com/engine/reference/builder/#onbuild

The gist of it is that it reverses the standard approach: in lieu of Dockerfile explicitly adding files and running commands, ONBUILD provides a canvas so that one just need to fill out the blanks.

Let’s create such a "parent" Dockerfile.

maven.Dockerfile
FROM maven:3.6.0-alpine

WORKDIR app
ONBUILD COPY . /app
ONBUILD RUN mvn package

From this file, it’s possible to create the image:

docker build -f maven.Dockerfile -t mavenbase .
This doesn’t require any project but the Dockerfile itself.

At any later point in time, from any Maven-compliant folder structure, it’s possible to create a thinned-down Dockerfile and build the app using the build image:

project.Dockerfile
FROM mavenbase:latest  (1)
1 Yes, only a single directive necessary!
docker build -f app.Dockerfile -t myapp .

Conclusion

Beyond simple usages, Docker allows offers a wide range of features. Among them, the ONBUILD directive allows to drastically reduce Dockerfile size by factoring repetitive configuration in a parent image.

Nicolas Fränkel

Nicolas Fränkel

Nicolas Fränkel is a Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Currently working for Hazelcast. Also double as a teacher in universities and higher education schools, a trainer and triples as a book author.

Read More