When you have a Java app, you may want to create a Docker image for it and deploy to Kubernetes. There are two steps here:

  1. Build Java source code and package as a JAR file.
  2. Build a Docker image from the JAR file with JDK.

With a normal build process, these two steps are separated. The first step is done with Maven/Gradle on the local machine. The second step is done by creating an image from Dockerfile using local files generated in the first step. This may not be possible when using continuous integration provided by public container registries like Docker Hub or Quay.io. This is because these registries only support building Docker images.

With the help of Docker's multi-stage builds, we can easily combine these two steps into one.

Given a Spring Boot app, the Dockerfile below can be used to build images from source code. The first stage uses the Maven image as the base. After copying src directory and pom.xml file to the image, Maven is used to build the Java source code. builder is the name of this stage. After the build, the /build/target directory contains the JAR file.

The second stage uses OpenJDK 11 Alpine image as the base image, the COPY command copies the JAR file built in the first stage to the current image. The option --from=builder specifies the source of copy action.

FROM maven:3.6.3-openjdk-11 AS builder
RUN mkdir /build
ADD src /build/src
ADD pom.xml /build
RUN cd /build && mvn -B -ntp package

FROM adoptopenjdk/openjdk11:alpine-jre
COPY --from=builder /build/target/docker-build-test-0.0.1-SNAPSHOT.jar /app.jar
CMD ["java", "-jar", "/app.jar"]

When this Dockerfile is built, the result image contains only the JDK and JAR file.