Skip to content

Commit

Permalink
Update the multi-stage Docker build example
Browse files Browse the repository at this point in the history
The change follows the discussion from quarkusio#16881.
It avoids relying on the centos-quarkus-maven image that should be deprecated.
Instead, it relies on the native-image image, and uses the maven/gradle wrappers.
It also allows using Mandrel easily.

Fix quarkusio#16881.
  • Loading branch information
cescoffier committed May 2, 2021
1 parent a70fba6 commit 2b13399
Showing 1 changed file with 38 additions and 23 deletions.
61 changes: 38 additions & 23 deletions docs/src/main/asciidoc/building-native-image.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -498,29 +498,35 @@ NOTE: If you are interested in tiny Docker images, check the {quarkus-images-url

=== Using a multi-stage Docker build

The previous section showed you how to build a native executable using Maven, but implicitly required that the proper GraalVM version be installed on the building machine (be it your local machine or your CI/CD infrastructure).
The previous section showed you how to build a native executable using Maven or Gradle, but it requires you to have created the native executable first.
In addition, this native executable must be a Linux 64 bits executable.

In cases where the GraalVM requirement cannot be met, you can use Docker to perform the Maven or Gradle build by using a multi-stage Docker build. A multi-stage Docker build is like two Dockerfile files combined in one, the first is used to build the artifact used by the second.
You may want to build the native executable directly in a container without having a final container containing the build tools.
That approach is possible with a multi-stage Docker build:

In this guide we will use the first stage to generate the native executable and the second stage to create our runtime image.
1. The first stage builds the native executable using Maven or Gradle
2. The second stage is a minimal image copying the produced native executable

Such a multi-stage build can be achieved as follows:

Sample Dockerfile for building with Maven:
[source,dockerfile,subs=attributes+]
----
## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/centos-quarkus-maven:{graalvm-flavor} AS build
COPY pom.xml /usr/src/app/
RUN mvn -f /usr/src/app/pom.xml -B de.qaware.maven:go-offline-maven-plugin:1.2.5:resolve-dependencies
COPY src /usr/src/app/src
USER root
RUN chown -R quarkus /usr/src/app
FROM quay.io/quarkus/ubi-quarkus-native-image:21.0.0-java11 AS build
COPY pom.xml /project/
COPY mvnw /project/mvnw
COPY .mvn /project/.mvn
USER quarkus
RUN mvn -f /usr/src/app/pom.xml -Pnative clean package
WORKDIR /project
RUN ./mvnw -B org.apache.maven.plugins:maven-dependency-plugin:3.1.2:go-offline
COPY src /project/src
RUN ./mvnw package -Pnative
## Stage 2 : create the docker final image
FROM registry.access.redhat.com/ubi8/ubi-minimal
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3
WORKDIR /work/
COPY --from=build /usr/src/app/target/*-runner /work/application
COPY --from=build /project/target/*-runner /work/application
# set up permissions for user `1001`
RUN chmod 775 /work /work/application \
Expand All @@ -534,26 +540,32 @@ USER 1001
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
----

NOTE: This multi-stage Docker builds copies the Maven Wrapper from the host machine.
The Maven wrapper (or the Gradle wrapper) is a convenient way to provide a specific tool version.
It avoids having to create a base image with Maven and Gradle.
To provision the Maven Wrapper in your project, use: `mvn -N io.takari:maven:0.7.7:wrapper`

Save this file in `src/main/docker/Dockerfile.multistage` as it is not included in the getting started quickstart.

Sample Dockerfile for building with Gradle:
[source,dockerfile,subs=attributes+]
----
## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/centos-quarkus-maven:{graalvm-flavor} AS build
COPY src /usr/src/app/src
COPY build.gradle /usr/src/app
COPY settings.gradle /usr/src/app
COPY gradle.properties /usr/src/app
USER root
RUN chown -R quarkus /usr/src/app
FROM quay.io/quarkus/ubi-quarkus-native-image:21.0.0-java11 AS build
COPY gradlew /project/gradlew
COPY gradle /project/gradle
COPY build.gradle /project/
COPY settings.gradle /project/
COPY gradle.properties /project/
USER quarkus
RUN gradle -b /usr/src/app/build.gradle clean buildNative
WORKDIR /project
COPY src /project/src
RUN gradle -b /project/build.gradle buildNative
## Stage 2 : create the docker final image
FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY --from=build /usr/src/app/build/*-runner /work/application
COPY --from=build /project/build/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
Expand All @@ -563,15 +575,15 @@ If you are using Gradle in your project, you can use this sample Dockerfile. Sa

[WARNING]
====
Before launching our Docker build, we need to update the default `.dockerignore` file as it filters everything except the `target` directory and as we plan to build inside a container we need to be able to copy the `src` directory. So edit your `.dockerignore` and remove or comment its content.
Before launching our Docker build, we need to update the default `.dockerignore` file as it filters everything except the `target` directory. As we plan to build inside a container, we need to copy the `src` directory. Thus, edit your `.dockerignore` and update the content.
====

[source,bash]
----
docker build -f src/main/docker/Dockerfile.multistage -t quarkus-quickstart/getting-started .
----

And finally, run it with:
And, finally, run it with:

[source,bash]
----
Expand All @@ -585,6 +597,9 @@ If you need SSL support in your native executable, you can easily include the ne
Please see link:native-and-ssl#working-with-containers[our Using SSL With Native Executables guide] for more information.
====

NOTE: To use Mandrel instead of GraalVM CE, update the `FROM` clause to: `FROM quay.io/quarkus/ubi-quarkus-mandrel:$TAG AS build`.
`$TAG` can be found on the https://quay.io/repository/quarkus/ubi-quarkus-mandrel?tab=tags[Quarkus Mandrel Images Tags page].

== Debugging native executable

Starting with Oracle GraalVM 20.2 or Mandrel 20.1,
Expand Down

0 comments on commit 2b13399

Please sign in to comment.