Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,25 +111,25 @@ auto-disables `contentCache` on resource-based components (such as `xslt`) whose
the route. Set `camel.component.<name>.contentCache=true` (or pass `?contentCache=true` on the
URI) to opt back in to caching during dev mode.

==== Unified `--packaging` option for `camel export`
==== Container-optimized layered Docker packaging for `camel export`

A new `--packaging` option has been added to `camel export` that works across all three runtimes
(Camel Main, Spring Boot, and Quarkus). It replaces the Quarkus-specific `--quarkus-package-type`
option, which is now deprecated.
The `camel export` command now generates Dockerfiles optimized for container image layer caching
across all three runtimes. Previously, Camel Main and Spring Boot exports produced a single-layer
fat JAR Dockerfile; now each runtime uses a layered approach where dependencies (stable) and
application code (volatile) are in separate Docker layers.

Accepted values:

- `layered` or `fast-jar` — container-optimized packaging with separate dependency layers (default)
- `fat-jar` or `uber-jar` — single executable JAR

The default is `layered`, which produces Dockerfiles optimized for container image layer caching.
Each runtime implements layered packaging using its native mechanism:

- **Camel Main**: thin JAR with dependencies in a `lib/` folder
- **Spring Boot**: multi-stage Dockerfile using Spring Boot's built-in layer extraction
- **Quarkus**: fast-jar packaging (unchanged from the previous `--quarkus-package-type=fast-jar` default)
- **Camel Main**: the generated POM now includes `maven-jar-plugin` (with classpath manifest) and
`maven-dependency-plugin:copy-dependencies`. The Dockerfile copies `target/lib/` first (cached
dependency layer), then the thin `.original` JAR (small application layer).
- **Spring Boot**: a multi-stage Dockerfile using Spring Boot's `jarmode=tools extract --layers`
to split the fat JAR into 4 Docker layers (dependencies, spring-boot-loader,
snapshot-dependencies, application).
- **Quarkus**: unchanged — already uses fast-jar packaging with a 4-layer Dockerfile.

The deprecated `--quarkus-package-type` option continues to work for backward compatibility.
The Quarkus-specific `--quarkus-package-type` option is now deprecated and hidden from help output.
Quarkus exports always use fast-jar (layered) packaging.

==== Improved default `--quarkus-version`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ camel dependency copy [options]
| `--quarkus-artifact-id` _(deprecated)_ | Deprecated. This value is not used anymore. It is kept only for backwards compatibility and will be removed in Camel 5.x. Camel commands may use either 'quarkus-bom' or 'quarkus-camel-bom' artifactIds depending on the context. | quarkus-bom | String
| `--quarkus-ext-registry` | The base URI of Quarkus Extension Registry. The default is {@value RuntimeType#QUARKUS_EXTENSION_REGISTRY_BASE_URL} unless camel.jbang.quarkus.platform.url system property is set (the /client/platforms suffix is removed if present). | | String
| `--quarkus-group-id` | groupId of Quarkus Platform BOM; honored only if --quarkus-version is set | io.quarkus.platform | String
| `--quarkus-package-type` | Quarkus package type (uber-jar or fast-jar) | fast-jar | String
| `--quarkus-version` | version of Quarkus Platform BOM; the default value is looked up in Quarkus Extension Registry | | String
| `--quiet` | Will be quiet, only print when error occurs | false | boolean
| `--repo,--repos` | Additional maven repositories for download on-demand (Use commas to separate multiple repositories) | | String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ camel dependency list [options]
| `--quarkus-artifact-id` _(deprecated)_ | Deprecated. This value is not used anymore. It is kept only for backwards compatibility and will be removed in Camel 5.x. Camel commands may use either 'quarkus-bom' or 'quarkus-camel-bom' artifactIds depending on the context. | quarkus-bom | String
| `--quarkus-ext-registry` | The base URI of Quarkus Extension Registry. The default is {@value RuntimeType#QUARKUS_EXTENSION_REGISTRY_BASE_URL} unless camel.jbang.quarkus.platform.url system property is set (the /client/platforms suffix is removed if present). | | String
| `--quarkus-group-id` | groupId of Quarkus Platform BOM; honored only if --quarkus-version is set | io.quarkus.platform | String
| `--quarkus-package-type` | Quarkus package type (uber-jar or fast-jar) | fast-jar | String
| `--quarkus-version` | version of Quarkus Platform BOM; the default value is looked up in Quarkus Extension Registry | | String
| `--quiet` | Will be quiet, only print when error occurs | false | boolean
| `--repo,--repos` | Additional maven repositories for download on-demand (Use commas to separate multiple repositories) | | String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ camel dependency update [options]
| `--quarkus-artifact-id` _(deprecated)_ | Deprecated. This value is not used anymore. It is kept only for backwards compatibility and will be removed in Camel 5.x. Camel commands may use either 'quarkus-bom' or 'quarkus-camel-bom' artifactIds depending on the context. | quarkus-bom | String
| `--quarkus-ext-registry` | The base URI of Quarkus Extension Registry. The default is {@value RuntimeType#QUARKUS_EXTENSION_REGISTRY_BASE_URL} unless camel.jbang.quarkus.platform.url system property is set (the /client/platforms suffix is removed if present). | | String
| `--quarkus-group-id` | groupId of Quarkus Platform BOM; honored only if --quarkus-version is set | io.quarkus.platform | String
| `--quarkus-package-type` | Quarkus package type (uber-jar or fast-jar) | fast-jar | String
| `--quarkus-version` | version of Quarkus Platform BOM; the default value is looked up in Quarkus Extension Registry | | String
| `--quiet` | Will be quiet, only print when error occurs | false | boolean
| `--repo,--repos` | Additional maven repositories for download on-demand (Use commas to separate multiple repositories) | | String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ camel export [options]
| `--quarkus-artifact-id` _(deprecated)_ | Deprecated. This value is not used anymore. It is kept only for backwards compatibility and will be removed in Camel 5.x. Camel commands may use either 'quarkus-bom' or 'quarkus-camel-bom' artifactIds depending on the context. | quarkus-bom | String
| `--quarkus-ext-registry` | The base URI of Quarkus Extension Registry. The default is {@value RuntimeType#QUARKUS_EXTENSION_REGISTRY_BASE_URL} unless camel.jbang.quarkus.platform.url system property is set (the /client/platforms suffix is removed if present). | | String
| `--quarkus-group-id` | groupId of Quarkus Platform BOM; honored only if --quarkus-version is set | io.quarkus.platform | String
| `--quarkus-package-type` | Quarkus package type (uber-jar or fast-jar) | fast-jar | String
| `--quarkus-version` | version of Quarkus Platform BOM; the default value is looked up in Quarkus Extension Registry | | String
| `--quiet` | Will be quiet, only print when error occurs | false | boolean
| `--repo,--repos` | Additional maven repositories for download on-demand (Use commas to separate multiple repositories) | | String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ camel sbom [options]
| `--quarkus-artifact-id` _(deprecated)_ | Deprecated. This value is not used anymore. It is kept only for backwards compatibility and will be removed in Camel 5.x. Camel commands may use either 'quarkus-bom' or 'quarkus-camel-bom' artifactIds depending on the context. | quarkus-bom | String
| `--quarkus-ext-registry` | The base URI of Quarkus Extension Registry. The default is {@value RuntimeType#QUARKUS_EXTENSION_REGISTRY_BASE_URL} unless camel.jbang.quarkus.platform.url system property is set (the /client/platforms suffix is removed if present). | | String
| `--quarkus-group-id` | groupId of Quarkus Platform BOM; honored only if --quarkus-version is set | io.quarkus.platform | String
| `--quarkus-package-type` | Quarkus package type (uber-jar or fast-jar) | fast-jar | String
| `--quarkus-version` | version of Quarkus Platform BOM; the default value is looked up in Quarkus Extension Registry | | String
| `--quiet` | Will be quiet, only print when error occurs | false | boolean
| `--repo,--repos` | Additional maven repositories for download on-demand (Use commas to separate multiple repositories) | | String
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -321,18 +321,23 @@ protected void copyDockerFiles(String buildDir) throws Exception {
model.put("Version", ids[2]);
model.put("AppJar", ids[1] + "-" + ids[2] + ".jar");

String ftlName = "Dockerfile" + javaVersion + ".ftl";
String ftlName = getDockerfileTemplateName() + javaVersion + ".ftl";
String context;
try {
context = TemplateHelper.processTemplate(ftlName, model);
} catch (IOException e) {
// fallback to JDK 21 template
String fallback = getDockerfileTemplateName() + "21.ftl";
printer().printf("No Dockerfile template for Java %s, falling back to Java 21 template%n", javaVersion);
context = TemplateHelper.processTemplate("Dockerfile21.ftl", model);
context = TemplateHelper.processTemplate(fallback, model);
}
Files.writeString(docker.resolve("Dockerfile"), context);
}

protected String getDockerfileTemplateName() {
return "Dockerfile";
}

// Copy the readme.md into the same Maven project root directory.
protected void copyReadme(String buildDir, String appJar) throws Exception {
String[] ids = gav.split(":");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,11 @@ public abstract class ExportBaseCommand extends CamelCommand {
@CommandLine.Mixin
protected QuarkusPlatformMixin quarkusPlatform;

@Deprecated
@CommandLine.Option(names = { "--quarkus-package-type" },
description = "Quarkus package type (uber-jar or fast-jar)",
defaultValue = "fast-jar")
description = "Deprecated: Quarkus always uses fast-jar (layered) packaging",
defaultValue = "fast-jar",
hidden = true)
protected String quarkusPackageType = "fast-jar";

@CommandLine.Option(names = { "--maven-wrapper" }, defaultValue = "true",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,15 +319,14 @@ protected String applicationPropertyLine(String key, String value) {
protected void copyDockerFiles(String buildDir) throws Exception {
Path dockerSrc = Path.of(buildDir).resolve("src/main/docker");
if ("uber-jar".equals(quarkusPackageType)) {
// For uber-jar, the generic Dockerfile works as-is
super.copyDockerFiles(buildDir);
} else {
// For fast-jar, use a Quarkus-specific JVM Dockerfile
Files.createDirectories(dockerSrc);
InputStream is
= ExportQuarkus.class.getClassLoader().getResourceAsStream("quarkus-docker/Dockerfile.jvm");
if (is != null) {
PathUtils.copyFromStream(is, dockerSrc.resolve("Dockerfile"), true);
try (InputStream is
= ExportQuarkus.class.getClassLoader().getResourceAsStream("quarkus-docker/Dockerfile.jvm")) {
if (is != null) {
PathUtils.copyFromStream(is, dockerSrc.resolve("Dockerfile"), false);
}
}
}

Expand All @@ -339,9 +338,11 @@ protected void copyDockerFiles(String buildDir) throws Exception {

// Quarkus-specific Dockerfiles for native builds
for (String dockerfile : List.of("Dockerfile.native", "Dockerfile.native-micro")) {
InputStream is = ExportQuarkus.class.getClassLoader().getResourceAsStream("quarkus-docker/" + dockerfile);
if (is != null) {
PathUtils.copyFromStream(is, dockerSrc.resolve(dockerfile), true);
try (InputStream is
= ExportQuarkus.class.getClassLoader().getResourceAsStream("quarkus-docker/" + dockerfile)) {
if (is != null) {
PathUtils.copyFromStream(is, dockerSrc.resolve(dockerfile), false);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,11 @@ private static String legacyMavenRepositoriesAsPomXml(String repos) {
return sb.toString();
}

@Override
protected String getDockerfileTemplateName() {
return "Dockerfile-spring-boot";
}

@Override
protected Set<String> resolveDependencies(Path settings, Path profile) throws Exception {
Set<String> answer = super.resolveDependencies(settings, profile);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<#--

Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

-->
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

####
# Multi-stage layered Dockerfile for Spring Boot (container-optimized).
#
# Uses Spring Boot's built-in layer extraction to produce optimized Docker layers.
# Dependencies (most stable) are copied first, application code (most volatile) last.
#
# ./mvnw clean package
# docker build -f src/main/docker/Dockerfile -t [=ArtifactId]:[=Version] .
# docker run -it [=ArtifactId]:[=Version]
#
###

# Stage 1: Extract Spring Boot layers
FROM registry.access.redhat.com/ubi9/openjdk-21:1.24 AS builder
WORKDIR /builder
COPY target/[=AppJar] application.jar
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted

# Stage 2: Build the optimized image
FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.24

COPY --from=builder --chown=185 /builder/extracted/dependencies/ /deployments/
COPY --from=builder --chown=185 /builder/extracted/spring-boot-loader/ /deployments/
COPY --from=builder --chown=185 /builder/extracted/snapshot-dependencies/ /deployments/
COPY --from=builder --chown=185 /builder/extracted/application/ /deployments/

# Uncomment to expose any given port
# EXPOSE 8080
USER 185
WORKDIR /deployments

ENTRYPOINT ["java", "-jar", "application.jar"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<#--

Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

-->
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

####
# Multi-stage layered Dockerfile for Spring Boot (container-optimized).
#
# Uses Spring Boot's built-in layer extraction to produce optimized Docker layers.
# Dependencies (most stable) are copied first, application code (most volatile) last.
#
# ./mvnw clean package
# docker build -f src/main/docker/Dockerfile -t [=ArtifactId]:[=Version] .
# docker run -it [=ArtifactId]:[=Version]
#
###

# Stage 1: Extract Spring Boot layers
FROM registry.access.redhat.com/ubi9/openjdk-25:1.24 AS builder
WORKDIR /builder
COPY target/[=AppJar] application.jar
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted

# Stage 2: Build the optimized image
FROM registry.access.redhat.com/ubi9/openjdk-25-runtime:1.24

COPY --from=builder --chown=185 /builder/extracted/dependencies/ /deployments/
COPY --from=builder --chown=185 /builder/extracted/spring-boot-loader/ /deployments/
COPY --from=builder --chown=185 /builder/extracted/snapshot-dependencies/ /deployments/
COPY --from=builder --chown=185 /builder/extracted/application/ /deployments/

# Uncomment to expose any given port
# EXPOSE 8080
USER 185
WORKDIR /deployments

ENTRYPOINT ["java", "-jar", "application.jar"]
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@

####
# This Dockerfile is used in order to build a container that runs the Camel application
# using layered packaging for optimized container image caching.
#
# ./mvnw clean package
# docker build -f src/main/docker/Dockerfile -t [=ArtifactId]:[=Version] .
# docker run -it [=ArtifactId]:[=Version]
#
# Dependencies are copied first (changes infrequently - cached layer),
# then the application JAR (changes frequently - small layer).
#
# This image uses the `run-java.sh` script to run the application.
# This scripts computes the command line to execute your Java application, and
# includes memory/GC tuning.
Expand Down Expand Up @@ -100,15 +104,16 @@
# when running the container
#
###
FROM registry.access.redhat.com/ubi9/openjdk-21:1.23
FROM registry.access.redhat.com/ubi9/openjdk-21:1.24

COPY --chown=185 target/[=AppJar] /deployments/
# Copy dependencies first for better layer caching
COPY --chown=185 target/lib/ /deployments/lib/
# Copy application JAR (the .original is the thin JAR before repackaging)
COPY --chown=185 target/[=AppJar].original /deployments/[=AppJar]

# Uncomment to expose any given port
# EXPOSE 8080
USER 185
# Uncomment to provide any Java option
# ENV JAVA_OPTS=""
ENV JAVA_APP_JAR="/deployments/[=AppJar]"

ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
Loading