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 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:
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 |
|3||Copy the current host directory to the image |
|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.
Among the many directives available in the syntax of Dockerfiles is the
ONBUILDinstruction 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
FROMinstruction in the downstream
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.
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:
FROM mavenbase:latest (1)
|1||Yes, only a single directive necessary!|
docker build -f app.Dockerfile -t myapp .
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.