Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Containers

A container is a way to package an application together with everything it needs to run: Java, libraries, settings. An image is the template of a container: you build it once and run it anywhere — on a laptop, a server, in Kubernetes. The most common tool is Docker. Quarkus prepares a project for containers from the first minute: the generator has already added Dockerfiles for different build types.

Ready-made Dockerfiles

FileWhat it packages
src/main/docker/Dockerfile.jvmThe quarkus-app folder on the JVM — the main option
src/main/docker/Dockerfile.legacy-jarThe old jar format
src/main/docker/Dockerfile.nativeA native executable for Linux
src/main/docker/Dockerfile.native-microA native executable on a minimal image

The essence of Dockerfile.jvm:

FROM registry.access.redhat.com/ubi9/openjdk-25-runtime:1.24
 
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
 
EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
 
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]

The base image already contains Java 25. The quarkus-app folders are copied as separate layers: the libraries in lib rarely change, so on a rebuild Docker takes that layer from its cache. The application runs as user 185, not as an administrator.

Building and running the image

The commands are written in a comment at the top of the same file:

./mvnw package
docker build -f src/main/docker/Dockerfile.jvm -t quarkus/blog-jvm .
docker run -i --rm -p 8080:8080 quarkus/blog-jvm

First Maven builds target/quarkus-app, then Docker packages it into the quarkus/blog-jvm image, and the container starts with port 8080 forwarded. Once it runs, the API is available at the same address, http://localhost:8080/posts.

For the native option: ./mvnw package -Dnative -Dquarkus.native.container-build=true, then docker build -f src/main/docker/Dockerfile.native -t quarkus/blog .. Such an image starts in milliseconds and takes noticeably less space.

Container settings

One image serves all environments, and the differences are passed as environment variables with -e:

docker run -i --rm -p 8080:8080 \
    -e BLOG_TITLE="Anna's blog" \
    -e QUARKUS_DATASOURCE_JDBC_URL=jdbc:h2:mem:blog \
    quarkus/blog-jvm

Here the H2 database lives in the container's memory. In a real project you pass the PostgreSQL address, login and password here — and no secret stays in the image.

Building an image without a Dockerfile

Quarkus can build an image itself as part of package. The container-image-docker, container-image-podman and container-image-jib extensions do this (Jib builds an image even without Docker installed):

./mvnw quarkus:add-extension -Dextensions="container-image-jib"
./mvnw package -Dquarkus.container-image.build=true

The image name comes from the project's groupId, artifactId and version; the quarkus.container-image.* settings change it. The kubernetes extension additionally generates Kubernetes manifests with the health checks from the /q/health lesson already wired in.

Common mistake

docker build does not compile Java code — it only copies the ready target/quarkus-app folder. If you forget ./mvnw package or run mvn clean before building the image, Docker reports that it cannot find target/quarkus-app/lib. And if the code changed but package was not run, the image gets the old version. Always build the application before docker build. The .dockerignore file from the generator lets only the target folder into Docker, so the sources never end up in the image.

Thanks for reading!

Donate to the site — we work hard for you.