Containerizing virtual thread applications
In another blog post, we explored how to implement a CRUD application with Quarkus to harness the power of virtual threads.
This post continues from that point, explaining how to containerize the application.
Containerization involves packaging the application into a container image, and we’ll use the quarkus-container-image-jib
extension for this purpose.
Quarkus offers other extensions for containerization, such as quarkus-container-image-docker
, so choose the one that suits your preference.
Packaging an application using virtual threads is not different from packaging a regular application. Quarkus hides all the complexity, selecting the right base image and configuring the native image build process to use the right flags.
The full code for this blog post is available in the crud-example
directory of the virtual-threads-demos GitHub repository.
Adding Jib to the Project
First, add the quarkus-container-image-jib
extension to the project:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-jib</artifactId>
</dependency>
Next, open the application.properties
file and add the following properties:
quarkus.container-image.build=true (1)
quarkus.container-image.name=virtual-threads-demos-${quarkus.application.name} (2)
-
Enable container image build; every
mvn package
run will build a container image. -
Define the name of the container image. The
${quarkus.application.name}
placeholder is replaced by the application name, which iscrud-example
in our case.
Building the Container Image for the JVM
To create the container image for the Java application, run the following command:
$ mvn clean package
The logs will show the container image build process, with the image being built using the registry.access.redhat.com/ubi8/openjdk-21-runtime:1.18
base image.
This image is automatically selected by Quarkus as the project uses Java 21.
Take note of the resulting image name: clement/virtual-threads-demos-crud-example:1.0.0-SNAPSHOT
. The first part is your username by default, do do not forget to change it in the other commands.
You can run the container image with:
$ docker run -it \
-p8080:8080 \
-e QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://docker.for.mac.localhost/rest-crud \
clement/virtual-threads-demos-crud-example:1.0.0-SNAPSHOT
Ensure to replace clement
with your username.
If you are running on ARM64, you may encounter a warning regarding the image’s platform mismatch.
You can override this using: $ mvn clean package -DskipTests -Dquarkus.jib.platforms=linuxarm64 .
|
Building the Container Image for the Native Executable
To build the container image for the native executable, use the following command:
$ mvn package -DskipTests \
-Dnative \
-Dquarkus.native.container-build=true \
-Dquarkus.jib.platforms=linux/arm64
The -Dnative
flag enables native compilation, and -Dquarkus.jib.platforms=linux/arm64
specifies the target platform (required if you are on ARM64, as by default it will pick linux/amd64
).
Note the property quarkus.native.container-build=true
, which instructs Quarkus to use a container image to build the native executable, avoiding the need for GraalVM installation.
Run the container image with:
$ docker run -it \
-p8080:8080 \
-e QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://docker.for.mac.localhost/rest-crud \
clement/virtual-threads-demos-crud-example:1.0.0-SNAPSHOT
Use the same configuration trick for the database connection, and replace clement
with your username.
Pushing the Container Image
Quarkus can push the container image to a registry. To push to the GitHub container repository, use these properties:
quarkus.container-image.registry=ghcr.io
quarkus.container-image.group=cescoffier
quarkus.container-image.username=cescoffier
quarkus.container-image.password=${GITHUB_TOKEN}
The GITHUB_TOKEN
environment variable configures the GitHub token, which must have permission to create packages. Push the container image using:
$ mvn clean package -DskipTests -Dquarkus.container-image.push=true
Append -Dnative
for native images.
Multi-architecture container images can be created using:
$ mvn clean package -DskipTests -Dquarkus.container-image.push=true -Dquarkus.jib.platforms=linux/amd64,linux/arm64
This option is not applicable for native executables, howver, it is very convenient for JVM applications as you can then use the same container image on different platforms.
Summary
This blog post demonstrated how to containerize a virtual thread application using Quarkus and the Jib container image extension. Both JVM applications and native executables were covered.
Attentive readers would have seen that nothing is different from a regular application. Quarkus handles all the complexity, selecting the right base image and configuring the native image build process to use the right flags.