Docker 17.05 enabled the ability to perform multiple build stages in a single Dockerfile, copying files between them. This brings to regular Docker build a capability that I’ve previously talked about in the context of Rocker, and something that’s of particular use in a compiled language like Java. Let’s see what it would look like in the context of the WebSphere Liberty ferret sample.
The original Dockerfile looks as follows:
An error has occurred. Please try again later. |
We can see that it assumes that the application has already been built and just pulls in the WAR file, in this case from Maven Central. With a multi-stage build we can perform the build of the application and the build of the image in a single Dockerfile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
FROM maven:onbuild AS build FROM websphere-liberty # Install curl and then clean up after (Healthcheck uses curl) RUN apt-get update \ && apt-get install -y curl \ && rm -rf /var/lib/apt/lists/* COPY --from=build /usr/src/app/target/ferret-1.3-SNAPSHOT.war /config/dropins/ferret.war # Add healthcheck file to call then set it as the healthcheck COPY healthcheck /opt/ibm/docker HEALTHCHECK CMD /opt/ibm/docker/healthcheck |
The first line uses the Maven on-build image to build the application using the source in the same directory as the Dockerfile. Although the stages are given an index by default, naming them using the AS keyword makes the file much more readable. Further down in the Dockerfile we can see that the COPY command takes the built WAR file from the first stage and copies it into the Liberty dropins directory as before. The important thing about all of this is that the final image doesn’t end up with the application source in it, or Maven, or an SDK – just the artifacts that are needed at runtime – thereby keeping down the final image size.