Container Images
Container Image extensions
Jib
The extension quarkus-container-image-jib
is powered by Jib for performing container image builds.
The major benefit of using Jib with Quarkus is that all the dependencies (everything found under target/lib
) are cached in a different layer than the actual application making rebuilds really fast and small (when it comes to pushing).
Another important benefit of using this extension is that it provides the ability to create a container image without having to have any dedicated client side tooling (like Docker) or running daemon processes (like the Docker daemon)
when all that is needed is the ability to push to a container image registry.
To use this feature, add the following extension to your project:
quarkus extension add 'container-image-jib'
./mvnw quarkus:add-extension -Dextensions="container-image-jib"
./gradlew addExtension --extensions="container-image-jib"
In situations where all that is needed to build a container image and no push to a registry is necessary (essentially by having set quarkus.container-image.build=true and left quarkus.container-image.push unset - it defaults to false ), then this extension creates a container image and registers
it with the Docker daemon. This means that although Docker isn’t used to build the image, it is nevertheless necessary. Also note that using this mode, the built container image will
show up when executing docker images .
|
Including extra files
There are cases when additional files (other than ones produced by the Quarkus build) need to be added to a container image.
To support these cases, Quarkus copies any file under src/main/jib
into the built container image (which is essentially the same
idea that the Jib Maven and Gradle plugins support).
For example, the presence of src/main/jib/foo/bar
would result in /foo/bar
being added into the container filesystem.
JVM Debugging
There are cases where the built container image may need to have Java debugging conditionally enabled at runtime.
When the base image has not been changed (and therefore ubi8/openjdk-11-runtime
or ubi8/openjdk-17-runtime
is used), then the quarkus.jib.jvm-additional-arguments
configuration property can be used in order to
make the JVM listen on the debug port at startup.
The exact configuration is:
quarkus.jib.jvm-additional-arguments=-agentlib:jdwp=transport=dt_socket\\,server=y\\,suspend=n\\,address=*:5005
Other base images might provide launch scripts that enable debugging when an environment variable is set, in which case you would set than environment variable when launching the container.
Finally, the quarkus.jib.jvm-entrypoint
configuration property can be used to completely override the container entry point and can thus be used to either hard code the JVM debug configuration or point to a script that handles the details.
Docker
The extension quarkus-container-image-docker
is using the Docker binary and the generated Dockerfiles under src/main/docker
in order to perform Docker builds.
To use this feature, add the following extension to your project.
quarkus extension add 'container-image-docker'
./mvnw quarkus:add-extension -Dextensions="container-image-docker"
./gradlew addExtension --extensions="container-image-docker"
S2I
The extension quarkus-container-image-s2i
is using S2I binary builds in order to perform container builds inside the OpenShift cluster.
The idea behind the binary build is that you just upload the artifact and its dependencies to the cluster and during the build they will be merged to a builder image (defaults to fabric8/s2i-java
).
The benefit of this approach, is that it can be combined with OpenShift’s DeploymentConfig
that makes it easy to roll out changes to the cluster.
To use this feature, add the following extension to your project.
quarkus extension add 'container-image-s2i'
./mvnw quarkus:add-extension -Dextensions="container-image-s2i"
./gradlew addExtension --extensions="container-image-s2i"
S2I builds require creating a BuildConfig
and two ImageStream
resources, one for the builder image and one for the output image.
The creation of such objects is being taken care of by the Quarkus Kubernetes extension.
Buildpack
The extension quarkus-container-image-buildpack
is using buildpacks in order to perform container image builds.
Under the hood buildpacks will use a Docker daemon for the actual build.
While buildpacks support alternatives to Docker, this extension will only work with Docker.
Additionally, the user will have to configure which build image to use (no default image is provided). For example:
quarkus.buildpack.jvm-builder-image=<jvm builder image>
or for native:
quarkus.buildpack.native-builder-image=<native builder image>
To use this feature, add the following extension to your project.
quarkus extension add 'container-image-buildpack'
./mvnw quarkus:add-extension -Dextensions="container-image-buildpack"
./gradlew addExtension --extensions="container-image-buildpack"
When using the buildpack container image extension it is strongly advised to avoid adding quarkus.container-image.build=true in your properties configuration as it might trigger nesting builds within builds. It’s preferable to pass it as an option to the build command instead.
|
Building
To build a container image for your project, quarkus.container-image.build=true
needs to be set using any of the ways that Quarkus supports.
quarkus build -Dquarkus.container-image.build=true
./mvnw clean package -Dquarkus.container-image.build=true
./gradlew build -Dquarkus.container-image.build=true
If you ever want to build a native container image and already have an existing native image you can set -Dquarkus.native.reuse-existing=true and the native image build will not be re-run.
|
Using @QuarkusIntegrationTest
To run tests on the resulting image, quarkus.container-image.build=true
needs to be set using any of the ways that Quarkus supports.
./mvnw verify -Dquarkus.container-image.build=true
./gradlew quarkusIntTest -Dquarkus.container-image.build=true
Pushing
To push a container image for your project, quarkus.container-image.push=true
needs to be set using any of the ways that Quarkus supports.
quarkus build -Dquarkus.container-image.push=true
./mvnw clean package -Dquarkus.container-image.push=true
./gradlew build -Dquarkus.container-image.push=true
If no registry is set (using quarkus.container-image.registry ) then docker.io will be used as the default.
|
Selecting among multiple extensions
It does not make sense to use multiple extension as part of the same build. When multiple container image extensions are present, an error will be raised to inform the user. The user can either remove the unneeded extensions or select one using application.properties
.
For example, if both container-image-docker
and container-image-s2i
are present and the user needs to use container-image-docker
:
quarkus.container-image.builder=docker
Customizing
The following properties can be used to customize the container image build process.
Container Image Options
Configuration property fixed at build time - All other configuration properties are overridable at runtime
Type |
Default |
|
---|---|---|
The group the container image will be part of |
string |
|
The name of the container image. If not set defaults to the application name |
string |
|
The tag of the container image. If not set defaults to the application version |
string |
|
Additional tags of the container image. |
list of string |
|
The container registry to use |
string |
|
Represents the entire image string. If set, then |
string |
|
The username to use to authenticate with the registry where the built image will be pushed |
string |
|
The password to use to authenticate with the registry where the built image will be pushed |
string |
|
Whether or not insecure registries are allowed |
boolean |
|
Whether or not a image build will be performed. |
boolean |
|
Whether or not an image push will be performed. |
boolean |
|
The name of the container image extension to use (e.g. docker, jib, s2i). The option will be used in case multiple extensions are present. |
string |
|
Custom labels to add to the generated image. |
|
Using CI Environments
Various CI environments provide a ready to use container-image registry which can be combined with the container-image Quarkus extensions in order to effortlessly create and push a Quarkus application to said registry.
For example, GitLab provides such a registry and in the provided CI environment,
makes available the CI_REGISTRY_IMAGE
environment variable
(see GitLab’s documentation) for more information), which can be used in Quarkus like so:
quarkus.container-image.image=${CI_REGISTRY_IMAGE}
See this for more information on how to combine properties with environment variables. |
Jib Options
In addition to the generic container image options, the container-image-jib
also provides the following options:
Configuration property fixed at build time - All other configuration properties are overridable at runtime
Type |
Default |
|
---|---|---|
The base image to be used when a container image is being produced for the jar build. When the application is built against Java 17 or higher, |
string |
|
The base image to be used when a container image is being produced for the native binary build. The default is "quay.io/quarkus/quarkus-micro-image". You can also use "registry.access.redhat.com/ubi8/ubi-minimal" which is a bigger base image, but provide more built-in utilities such as the microdnf package manager. |
string |
|
The JVM arguments to pass to the JVM when starting the application |
list of string |
|
Additional JVM arguments to pass to the JVM when starting the application |
list of string |
|
Additional arguments to pass when starting the native application |
list of string |
|
If this is set, then it will be used as the entry point of the container image. There are a few things to be aware of when creating an entry point
- A valid entrypoint is jar package specific (see |
list of string |
|
If this is set, then it will be used as the entry point of the container image. There are a few things to be aware of when creating an entry point
- A valid entrypoint depends on the location of both the launching scripts and the native binary file. To that end it’s helpful to remember that the native application is added to the |
list of string |
|
The username to use to authenticate with the registry used to pull the base JVM image |
string |
|
The password to use to authenticate with the registry used to pull the base JVM image |
string |
|
The ports to expose |
list of int |
|
The user to use in generated image |
string |
|
The working directory to use in the generated image. The default value is chosen to work in accordance with the default base image. |
string |
|
Controls the optimization which skips downloading base image layers that exist in a target registry. If the user does not set this property, then read as false. If |
boolean |
|
List of target platforms. Each platform is defined using the pattern: |
list of string |
|
The path of a file that will be written containing the digest of the generated image. If the path is relative, is writen to the output directory of the build tool |
string |
|
The path of a file that will be written containing the id of the generated image. If the path is relative, is writen to the output directory of the build tool |
string |
|
Whether or not to operate offline. |
boolean |
|
Name of binary used to execute the docker commands. This is only used by Jib when the container image is being built locally. |
string |
|
Whether to set the creation time to the actual build time. Otherwise, the creation time will be set to the Unix epoch (00:00:00, January 1st, 1970 in UTC). See Jib FAQ for more information |
boolean |
|
Environment variables to add to the container image |
|
Docker Options
In addition to the generic container image options, the container-image-docker
also provides the following options:
Configuration property fixed at build time - All other configuration properties are overridable at runtime
Type |
Default |
|
---|---|---|
Path to the JVM Dockerfile. If not set ${project.root}/src/main/docker/Dockerfile.jvm will be used If set to an absolute path then the absolute path will be used, otherwise the path will be considered relative to the project root |
string |
|
Path to the JVM Dockerfile. If not set ${project.root}/src/main/docker/Dockerfile.native will be used If set to an absolute path then the absolute path will be used, otherwise the path will be considered relative to the project root |
string |
|
Images to consider as cache sources. Values are passed to |
list of string |
|
string |
||
Name of binary used to execute the docker commands. |
string |
|
Build args passed to docker via |
|
S2I Options
In addition to the generic container image options, the container-image-s2i
also provides the following options:
Configuration property fixed at build time - All other configuration properties are overridable at runtime
Type |
Default |
|
---|---|---|
The base image to be used when a container image is being produced for the jar build |
string |
|
The base image to be used when a container image is being produced for the native binary build |
string |
|
The JVM arguments to pass to the JVM when starting the application |
list of string |
|
Additional JVM arguments to pass to the JVM when starting the application |
list of string |
|
Additional arguments to pass when starting the native application |
list of string |
|
The directory where the jar is added during the assemble phase. This is dependent on the S2I image and should be supplied if a non default image is used. |
string |
|
The resulting filename of the jar in the S2I image. This option may be used if the selected S2I image uses a fixed name for the jar. |
string |
|
The directory where the native binary is added during the assemble phase. This is dependent on the S2I image and should be supplied if a non-default image is used. |
string |
|
The resulting filename of the native binary in the S2I image. This option may be used if the selected S2I image uses a fixed name for the native binary. |
string |
|
The build timeout. |
|
About the Duration format
The format for durations uses the standard You can also provide duration values starting with a number.
In this case, if the value consists only of a number, the converter treats the value as seconds.
Otherwise, |