As of v17.04, Dockerfiles now support multi-stage builds.
This is great as it means it’s no longer necessary to cram everything into a small number of layers to minimise image size.
Take this example that builds and runs a jar:
FROM java/8 COPY ./app /app RUN apt-get update && \ apt-get install -y -q gradle && \ gradle -b /app/build.gradle assemble && \ cp /app/build/app.jar /opt && \ rm -rf /app && \ apt-get purge -y gradle && \ rm -rf /var/caches/apt CMD ["java", "-jar", "/opt/app.jar"]
Four layers, and a big ugly
RUN statement that might as well be a separate
This can now be rewritten as:
FROM java/8 as build RUN apt-get update && apt-get install -y -q gradle COPY ./app /app RUN gradle -b /app/build.gradle assemble FROM java/8 as run COPY --from=build /app/build/app.jar /opt/app.jar CMD ["java", "-jar", "/opt/app.jar"]
More layers in total, but only three in the
Notice also that we now get cache layers for each build step, so if the gradle build fails because of a compilation error, the next build doesn’t need to go through the whole apt-get installation again.
We can also do away with housekeeping tasks like removing source files and build dependencies, because the entire build container can be discarded when finished with.