Docker containers provide the flexibility of development environments to match a production environment, to help isolate your application, and to minimize overhead. For self-contained executables, generated with GraalVM Native Image, containers are an obvious deployment choice.
To support container-based development, there are several GraalVM container images available, depending on the platform, the architecture, the Java version, and the edition:
This guide shows how to containerise a native executable for your Java application. You will use a GraalVM container image with Native Image to compile a Java application ahead-of-time into a native executable.
This guide uses the Spring Boot 3 Native Image Microservice example.
The example is a minimal REST-based API application, built on top of Spring Boot 3.
If you call the HTTP endpoint /jibber
, it will return some nonsense verse generated in the style of the Jabberwocky poem, by Lewis Carroll.
Download and install the latest Oracle GraalVM from Downloads. The easiest option is to use SDKMAN!. Run the following command to install Oracle GraalVM for JDK 17:
sdk install java 17.0.8-graal
Install and run a Docker-API compatible container runtime such as Rancher Desktop, Docker, or Podman.
Clone the GraalVM Demos repository:
git clone https://github.com/graalvm/graalvm-demos
Change directory to the demo directory:
cd spring-native-image
With the built-in support for GraalVM Native Image in Spring Boot 3, it has become much easier to compile a Spring Boot 3 application into a native executable.
Build a native executable:
./mvnw native:compile -Pnative
The -Pnative
profile is used to generate a native executable for your platform.
This will generate a native executable called benchmark-jibber in the target directory.
Run the native executable and put it into the background by appending &
:
./target/benchmark-jibber &
Call the endpoint using curl
:
curl http://localhost:8080/jibber
You should get a random nonsense verse.
Bring the application to the foreground using fg
, and then enter <CTRL-c>
to terminate the application.
The generated native executable is platform-dependent.
Containerise the native executable using the following command:
On Linux, containerise the native executable generated in the previous step using the following command:
docker build -f Dockerfiles/Dockerfile.native --build-arg APP_FILE=benchmark-jibber -t jibber-benchmark:native.0.0.1-SNAPSHOT .
On MacOS, Windows, or Linux, use multistage Docker builds to build a native executable inside a container, and package the native executable in a lightweight container image:
docker build -f Dockerfiles/Dockerfile -t jibber-benchmark:native.0.0.1-SNAPSHOT .
Run the application:
docker run --rm --name native -p 8080:8080 jibber-benchmark:native.0.0.1-SNAPSHOT
From a new terminal window, call the endpoint using curl
:
curl http://localhost:8080/jibber
It should generate a random nonsense verse.
To stop the application, first get the container id using docker ps
, and then run:
docker rm -f <container_id>
To delete the container images, first get the image id using docker images
, and then run:
docker rmi -f <image_1_id> <image_n_id>
In this guide, you saw how to use GraalVM container images to containerize a native executable for your Java application.
With GraalVM Native Image you can build a statically linked native executable by packaging the native executable directly into tiny containers such as scratch or distroless images. Continue to Build a Static or Mostly-Static Native Executable guide to learn more.