$ mvn package
Packaging an application
This plugin supports different <packaging>
types:
-
jar
(default): produces a runnable fat JAR. -
native-image
: generates a GraalVM native image. -
docker
: builds a Docker image with the application artifacts (compiled classes, resources, dependencies, etc). -
docker-native
: builds a Docker image with a GraalVM native image inside. -
docker-crac
: builds a Docker image containing a CRaC checkpointed application.
To package an application, mvn package
is the one-stop shop to produce the desired artifact. By default, applications
generated from Micronaut Launch have the packaging defined like
<packaging>${packaging}</packaging>
, so that you can do something like mvn package -Dpackaging=native-image
:
Packaging the application in a fat JAR
If the <packaging>
is set to jar
, this plugin will delegate to the maven-shade-plugin
to produce a JAR file. Its
configuration is defined in the io.micronaut:micronaut-parent
POM, and the defaults should be enough. Should you want
to customize how to produce the JAR file, refer to the
Maven Shade Plugin documentation.
Generating GraalVM native images
$ mvn package -Dpackaging=native-image
If the <packaging>
is set to native-image
, this plugin will delegate to the official GraalVM Maven Native plugin
(org.graalvm.buildtools:native-maven-plugin
) to generate a native image. Note that for this packaging to work,
you need to run locally a GraalVM JDK.
Refer to the Native Maven Plugin documentation for more information about how to customize the generated native image.
For example, to add --verbose
to the native image args, you should define:
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<buildArgs combine.children="append">
<buildArg>--verbose</buildArg>
</buildArgs>
</configuration>
</plugin>
Windows users
Sometimes, depending on how many classes are in the classpath you may see an error The command line is too long
when
building a native-image. This is a known issue
with Windows. To work around this you need to configure the Shade plugin in your pom.xml
and then configure the native image
plugin to use that shaded jar for building the native image:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>shaded</shadedClassifierName>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration combine.self="override">
<mainClass>${exec.mainClass}</mainClass>
<classpath>
<param>${project.build.directory}/${project.artifactId}-${project.version}-shaded.jar</param>
</classpath>
</configuration>
</plugin>
Then run:
mvn package (1)
mvn package -Dpackaging=native-image (2)
1 | Create the shaded runnable jar for the application. |
2 | Use the shaded runnable jar to build the native image. |
Building JVM-based Docker images
$ mvn package -Dpackaging=docker
If the <packaging>
is set to docker
, this plugin will use com.google.cloud.tools:jib-maven-plugin
to produce a
Docker image with the application artifacts (compiled classes, resources, dependencies, etc) inside.
The Docker image is built to a local Docker daemon (the equivalent of executing the jib::dockerBuild
goal).
Depending on the micronaut.runtime
property, the image built might be different. Options are:
-
Default runtime:
mvn package -Dpackaging=docker
. -
Oracle Cloud Function:
mvn package -Dpackaging=docker -Dmicronaut.runtime=oracle_function
. -
AWS Lambda (Java runtimes):
mvn package -Dpackaging=docker -Dmicronaut.runtime=lambda
.
You can use the mn:dockerfile
goal to generate the equivalent Dockerfile
. For example,
to generate the Dockerfile
for AWS Lambda, run mvn mn:dockerfile -Dpackaging=docker -Dmicronaut.runtime=lambda
.
Refer to the Jib Maven Plugin documentation to see what are the configuration options that can be used.
For example, you can define the jib-maven-plugin
in your POM as follows to pass additional JVM and application args:
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<configuration>
<container>
<jvmFlags>
<jvmFlag>-Dmy.property=example.value</jvmFlag>
<jvmFlag>-Xms512m</jvmFlag>
<jvmFlag>-Xdebug</jvmFlag>
</jvmFlags>
<args>
<arg>some</arg>
<arg>args</arg>
</args>
</container>
</configuration>
</plugin>
Bringing your own Dockerfile
$ mvn package -Dpackaging=docker
If there is a Dockerfile
in the project’s root directory, it will be used to build the image. The image will be built
using the target
folder as the context directory. This plugin will also prepare all the compile
and runtime
dependency JARs in the target/dependency
folder, so that in your Dockerfile
you can leverage this and do:
FROM ... ... COPY classes /home/app/classes COPY dependency/* /home/app/libs/ ... ENTRYPOINT ["java", "-cp", "/home/app/libs/*:/home/app/classes/", "com.example.app.Application"]
Building GraalVM-based Docker images
$ mvn package -Dpackaging=docker-native
If the <packaging>
is set to docker-native
, this plugin will use a Docker client to build and tag custom Docker
images. In this case, the micronaut.runtime
property will also determine how the image is prepared.
-
Default runtime.
-
Default image (dynamic):
mvn package -Dpackaging=docker-native
. -
Static image:
mvn package -Dpackaging=docker-native -Dmicronaut.native-image.static=true
. This uses GraalVM’s--static --libc=musl
flags and then puts the binary in ascratch
image. -
Mostly static image:
mvn package -Dpackaging=docker-native -Dmicronaut.native-image.base-image-run=gcr.io/distroless/cc-debian12 -Pgraalvm
. This will create a "mostly" static native image and adds automatically-H:+StaticExecutableWithDynamicLibC
flag. -
Custom image:
mvn package -Dpackaging=docker-native -Dmicronaut.native-image.base-image-run=your-own-image-for-run-the-native-image
-
-
Oracle Cloud Function:
mvn package -Dpackaging=docker-native -Dmicronaut.runtime=oracle_function
. -
AWS Lambda (custom runtime):
mvn package -Dpackaging=docker-native -Dmicronaut.runtime=lambda
.
The image built can be customised using Jib. In particular, you can set:
-
The base image, using
<from><image>
. If the base image comes from a registry that requires authentication, you can use<from><auth><username>
and<from><auth><password>
. Chek the Jib documentation for more details. -
The image name/tags that will be used for building, using either
<to><image>
and/or<to><tags>
.
You can also use some system properties from the command line:
-
jib.from.auth.username
. -
jib.from.auth.password
. -
jib.to.image
. -
jib.to.tags
. -
jib.to.auth.username
. -
jib.to.auth.password
. -
jib.to.credHelper
.
Note that changing the base image to a totally different one than the default might break image building, since the rest
of the build steps expect a certain base image. By default, the native images are built from an ghcr.io/graalvm/native-image-community
image.
In the case of AWS custom runtime, it starts from amazonlinux:2023
, and this cannot be changed. Also, in this case the
result is not a tagged Docker image, but a function.zip
archive that contains the launch script and the native binary.
Essentially, what you need to upload to AWS Lambda. Also in this case, the Micronaut Maven Plugin will detect the host
operating system architecture (based on the os.arch
Java system property) and will install the corresponding GraalVM
binary distribution inside the Docker image. This means that when running packaging from an X86_64 (Intel/AMD) machine,
the produced native image will be an amd64
binary, whilst on an ARM host (such as the new Mac M1) it will be an
aarch64
binary.
You can pass additional arguments to the executable in the following way:
<plugin>
<groupId>io.micronaut.maven</groupId>
<artifactId>micronaut-maven-plugin</artifactId>
<configuration>
<appArguments>
<appArgument>foo</appArgument>
<appArgument>bar</appArgument>
</appArguments>
</configuration>
</plugin>
Or when packaging:
$ mvn package -Dpackaging=docker-native -Dmn.appArgs="foo,bar"
Also, to pass additional arguments to the native-image
process:
<plugin>
<groupId>io.micronaut.maven</groupId>
<artifactId>micronaut-maven-plugin</artifactId>
<configuration>
<nativeImageBuildArgs>
<nativeImageBuildArg>--verbose</nativeImageBuildArg>
</nativeImageBuildArgs>
</configuration>
</plugin>
Or from the command line:
$ mvn package -Dpackaging=docker-native -Dmicronaut.native-image.args="--verbose"
Building CRaC-based Docker images
Warning: The Micronaut CRaC module is in experimental stages. Use at your own risk!
The CRaC (Coordinated Restore at Checkpoint) Project researches coordination of Java programs with mechanisms to checkpoint (make an image of, snapshot) a Java instance while it is executing. Restoring from the image could be a solution to some problems with the start-up and warm-up times.
Creation of a pre-warmed, checkpointed docker image cane be done with the following command:
$ mvn package -Dpackaging=docker-crac
This will first create an intermediate image that contains the application and all of its dependencies.
This image is then executed and warmed up via a warmup.sh
command, and a checkpoint is taken.
A final image is then built which contains this checkpoint.
You will then be able to run your image via:
docker run --cap-add=cap_sys_ptrace -p 8080:8080 <image-name>
The image built can be customised using Jib. In particular, you can set:
-
The base image, using
<from><image>
. -
The image name/tags that will be used for building, using either
<to><image>
and/or<to><tags>
.
Checking an application is ready
As part of the checkpointing process, the application will be tested until it is ready to recieve requests.
This is by default done by executing the command curl --output /dev/null --silent --head http://localhost:8080
, however you can override this by setting the crac.readiness
property in your build.
<properties>
<crac.readiness>curl --output /dev/null --silent --head https://localhost</crac.readiness>
</properties>
Customizing warmup
The default warmup script simply makes a request to port 8080 of the application.
However, you can specify your own by placing a Bash script named warmup.sh
in the root project folder.
For example, to hit the root endpoint 10 times, you could create a file with the following contents:
#!/bin/bash
for run in {1..10}; do
curl --output /dev/null --silent http://localhost:8080
done
Customizing the JDK
By default, the CRaC JDK used to build the image will be for the current system architecture and Java 17. These can be overridden by passing properties to the build:
<properties>
<crac.java.version>17</crac.java.version>
<crac.arch>amd64</crac.arch>
<crac.os>linux-glibc</crac.os>
</properties>
Currently only Java 17, and amd64 and aarch64 architectures are supported.
|