This is an automated email from the ASF dual-hosted git repository.

Croway pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new c631050a0d46 CAMEL-23601: camel-jbang - export layered Docker 
packaging for Main and Spring Boot
c631050a0d46 is described below

commit c631050a0d469a8ae5d94ae9c81ca716b08c812d
Author: Croway <[email protected]>
AuthorDate: Wed May 27 17:35:03 2026 +0200

    CAMEL-23601: camel-jbang - export layered Docker packaging for Main and 
Spring Boot
---
 .../ROOT/pages/camel-4x-upgrade-guide-4_21.adoc    | 28 +++++++++----------
 .../camel-jbang-dependency-copy.adoc               |  1 -
 .../camel-jbang-dependency-list.adoc               |  1 -
 .../camel-jbang-dependency-update.adoc             |  1 -
 .../pages/jbang-commands/camel-jbang-export.adoc   |  1 -
 .../pages/jbang-commands/camel-jbang-sbom.adoc     |  1 -
 .../META-INF/camel-jbang-commands-metadata.json    |  6 ++--
 .../camel/dsl/jbang/core/commands/Export.java      |  9 ++++--
 .../dsl/jbang/core/commands/ExportBaseCommand.java |  6 ++--
 .../dsl/jbang/core/commands/ExportQuarkus.java     | 19 +++++++------
 .../dsl/jbang/core/commands/ExportSpringBoot.java  |  5 ++++
 ...ckerfile25.ftl => Dockerfile-spring-boot21.ftl} | 24 ++++++++++------
 ...ckerfile25.ftl => Dockerfile-spring-boot25.ftl} | 24 ++++++++++------
 .../src/main/resources/templates/Dockerfile21.ftl  | 13 ++++++---
 .../src/main/resources/templates/Dockerfile25.ftl  | 21 +++++++-------
 .../src/main/resources/templates/main-pom.ftl      | 32 ++++++++++++++++++++++
 .../dsl/jbang/core/commands/ExportMainJibTest.java |  8 +++---
 .../jbang/core/commands/ExportMainJkubeTest.java   |  6 ++--
 18 files changed, 134 insertions(+), 72 deletions(-)

diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
index 7b264df8c03b..c4127f531c2e 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
@@ -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`
 
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc
 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc
index 1b85fcf61a1a..7bf8df7878d9 100644
--- 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc
+++ 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc
@@ -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
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc
 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc
index eac74643b73c..586494301fcd 100644
--- 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc
+++ 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc
@@ -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
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
index 6fbb722f4360..e106d7f7c8f1 100644
--- 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
+++ 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
@@ -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
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc
index dec20b4cb352..32209ab22df2 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc
@@ -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
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc
index 7d81ebe299d6..b15316ac0c93 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc
@@ -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
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
index d0d78976a693..392cb97ce616 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
@@ -7,13 +7,13 @@
     { "name": "completion", "fullName": "completion", "description": "Generate 
completion script for bash\/zsh", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Complete", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ] },
     { "name": "config", "fullName": "config", "description": "Get and set user 
configuration values", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.config.ConfigCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "get", 
"fullName": "config get", "description": "Display user configuration value", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.config. [...]
     { "name": "debug", "fullName": "debug", "description": "Debug local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Debug", 
"options": [ { "names": "--ago", "description": "Use ago instead of yyyy-MM-dd 
HH:mm:ss in timestamp.", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background", "description": "Run in the background", "defaultValue": 
"false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To  [...]
-    { "name": "dependency", "fullName": "dependency", "description": "Displays 
all Camel dependencies required to run", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.DependencyCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"copy", "fullName": "dependency copy", "description": "Copies all Camel 
dependencies required to run to a specific directory", "sourc [...]
+    { "name": "dependency", "fullName": "dependency", "description": "Displays 
all Camel dependencies required to run", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.DependencyCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"copy", "fullName": "dependency copy", "description": "Copies all Camel 
dependencies required to run to a specific directory", "sourc [...]
     { "name": "dirty", "fullName": "dirty", "description": "Check if there are 
dirty files from previous Camel runs that did not terminate gracefully", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.Dirty", 
"options": [ { "names": "--clean", "description": "Clean dirty files which are 
no longer in use", "defaultValue": "false", "javaType": "boolean", "type": 
"boolean" }, { "names": "-h,--help", "description": "Display the help and 
sub-commands", "javaType": "boolean", " [...]
     { "name": "doc", "fullName": "doc", "description": "Shows documentation 
for kamelet, component, and other Camel resources", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.catalog.CatalogDoc", "options": [ { 
"names": "--camel-version", "description": "To use a different Camel version 
than the default version", "javaType": "java.lang.String", "type": "string" }, 
{ "names": "--download", "description": "Whether to allow automatic downloading 
JAR dependencies (over the internet [...]
     { "name": "doctor", "fullName": "doctor", "description": "Checks the 
environment and reports potential issues", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Doctor", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ] },
     { "name": "eval", "fullName": "eval", "description": "Evaluate Camel 
expressions and scripts", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.EvalCommand", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ], "subcommands": [ { "name": "expression", 
"fullName": "eval expression", "description": "Evaluates Camel expression", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.action.EvalEx [...]
     { "name": "explain", "fullName": "explain", "description": "Explain what a 
Camel route does using AI\/LLM", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Explain", "options": [ { "names": 
"--api-key", "description": "API key for authentication. Also reads 
ANTHROPIC_API_KEY, OPENAI_API_KEY, or LLM_API_KEY env vars", "javaType": 
"java.lang.String", "type": "string" }, { "names": "--api-type", "description": 
"API type: 'ollama', 'openai' (OpenAI-compatible), or 'anthropic' (A [...]
-    { "name": "export", "fullName": "export", "description": "Export to other 
runtimes (Camel Main, Spring Boot, or Quarkus)", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Export", "options": [ { "names": 
"--build-property", "description": "Maven build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--camel-spring-boot-version", "description": "Camel version to use 
with Spring Boot", "javaType": "java.lang.String", "ty [...]
+    { "name": "export", "fullName": "export", "description": "Export to other 
runtimes (Camel Main, Spring Boot, or Quarkus)", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Export", "options": [ { "names": 
"--build-property", "description": "Maven build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--camel-spring-boot-version", "description": "Camel version to use 
with Spring Boot", "javaType": "java.lang.String", "ty [...]
     { "name": "get", "fullName": "get", "description": "Get status of Camel 
integrations", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.CamelStatus", "options": [ { 
"names": "--watch", "description": "Execute periodically and showing output 
fullscreen", "javaType": "boolean", "type": "boolean" }, { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ], "subcommands": [ { "name": "bean", 
"fullName": "get  [...]
     { "name": "harden", "fullName": "harden", "description": "Suggest security 
hardening for Camel routes using AI\/LLM", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Harden", "options": [ { "names": 
"--api-key", "description": "API key for authentication. Also reads 
OPENAI_API_KEY or LLM_API_KEY env vars", "javaType": "java.lang.String", 
"type": "string" }, { "names": "--api-type", "description": "API type: 'ollama' 
or 'openai' (OpenAI-compatible)", "defaultValue": "ollama", [...]
     { "name": "hawtio", "fullName": "hawtio", "description": "Launch Hawtio 
web console", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.Hawtio", "options": [ { 
"names": "--host", "description": "Hostname to bind the Hawtio web console to", 
"defaultValue": "127.0.0.1", "javaType": "java.lang.String", "type": "string" 
}, { "names": "--openUrl", "description": "To automatic open Hawtio web console 
in the web browser", "defaultValue": "true", "javaType": "boolean", "type": 
[...]
@@ -25,7 +25,7 @@
     { "name": "plugin", "fullName": "plugin", "description": "Manage plugins 
that add sub-commands to this CLI", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.plugin.PluginCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "add", 
"fullName": "plugin add", "description": "Add new plugin", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.plugin.PluginA [...]
     { "name": "ps", "fullName": "ps", "description": "List running Camel 
integrations", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.ListProcess", "options": [ { 
"names": "--json", "description": "Output in JSON Format", "javaType": 
"boolean", "type": "boolean" }, { "names": "--pid", "description": "List only 
pid in the output", "javaType": "boolean", "type": "boolean" }, { "names": 
"--remote", "description": "Break down counters into remote\/total pairs", 
"javaType": [...]
     { "name": "run", "fullName": "run", "description": "Run as local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Run", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, { [...]
-    { "name": "sbom", "fullName": "sbom", "description": "Generate a CycloneDX 
or SPDX SBOM for a specific project", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.SBOMGenerator", "options": [ { 
"names": "--build-property", "description": "Maven build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--camel-spring-boot-version", "description": "Camel version to use 
with Spring Boot", "javaType": "java.lang.String", "type" [...]
+    { "name": "sbom", "fullName": "sbom", "description": "Generate a CycloneDX 
or SPDX SBOM for a specific project", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.SBOMGenerator", "options": [ { 
"names": "--build-property", "description": "Maven build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--camel-spring-boot-version", "description": "Camel version to use 
with Spring Boot", "javaType": "java.lang.String", "type" [...]
     { "name": "script", "fullName": "script", "description": "Run Camel 
integration as shell script for terminal scripting", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Script", "options": [ { "names": 
"--logging", "description": "Can be used to turn on logging (logs to file in 
<user home>\/.camel directory)", "defaultValue": "false", "javaType": 
"boolean", "type": "boolean" }, { "names": "--logging-level", "description": 
"Logging level (ERROR, WARN, INFO, DEBUG, TRACE)", "d [...]
     { "name": "shell", "fullName": "shell", "description": "Interactive Camel 
JBang shell.", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Shell", 
"options": [ { "names": "-h,--help", "description": "Display the help and 
sub-commands", "javaType": "boolean", "type": "boolean" } ] },
     { "name": "stop", "fullName": "stop", "description": "Shuts down running 
Camel integrations", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.StopProcess", "options": [ { 
"names": "--kill", "description": "To force killing the process (SIGKILL)", 
"javaType": "boolean", "type": "boolean" }, { "names": "-h,--help", 
"description": "Display the help and sub-commands", "javaType": "boolean", 
"type": "boolean" } ] },
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
index 3761e475952b..27189e4f2eaa 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
@@ -321,18 +321,23 @@ public class Export extends ExportBaseCommand {
         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(":");
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
index 653298913249..8e17ee6c2899 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
@@ -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",
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
index 463e8d94fbae..f993a84bc88f 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
@@ -319,15 +319,14 @@ class ExportQuarkus extends Export {
     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);
+                }
             }
         }
 
@@ -339,9 +338,11 @@ class ExportQuarkus extends Export {
 
         // 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);
+                }
             }
         }
     }
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java
index bf4c81fc1a20..f991c786b34a 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java
@@ -385,6 +385,11 @@ class ExportSpringBoot extends Export {
         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);
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile25.ftl
 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile-spring-boot21.ftl
similarity index 65%
copy from 
dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile25.ftl
copy to 
dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile-spring-boot21.ftl
index 506abc971d60..e13ded8182e4 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile25.ftl
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile-spring-boot21.ftl
@@ -34,26 +34,34 @@
 #
 
 ####
-# This Dockerfile is used in order to build a container that runs the Camel 
application
+# 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]
 #
 ###
-FROM eclipse-temurin:25-jre-ubi9-minimal
 
-ENV LANGUAGE='en_US:en'
+# 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
 
-RUN mkdir /deployments
+# Stage 2: Build the optimized image
+FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.24
 
-COPY --chown=185 target/[=AppJar] /deployments/
+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
-# Uncomment to provide any Java option
-# ENV JAVA_OPTS=""
 WORKDIR /deployments
 
-ENTRYPOINT exec java $JAVA_OPTS -jar [=AppJar]
+ENTRYPOINT ["java", "-jar", "application.jar"]
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile25.ftl
 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile-spring-boot25.ftl
similarity index 65%
copy from 
dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile25.ftl
copy to 
dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile-spring-boot25.ftl
index 506abc971d60..cf15283b8137 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile25.ftl
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile-spring-boot25.ftl
@@ -34,26 +34,34 @@
 #
 
 ####
-# This Dockerfile is used in order to build a container that runs the Camel 
application
+# 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]
 #
 ###
-FROM eclipse-temurin:25-jre-ubi9-minimal
 
-ENV LANGUAGE='en_US:en'
+# 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
 
-RUN mkdir /deployments
+# Stage 2: Build the optimized image
+FROM registry.access.redhat.com/ubi9/openjdk-25-runtime:1.24
 
-COPY --chown=185 target/[=AppJar] /deployments/
+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
-# Uncomment to provide any Java option
-# ENV JAVA_OPTS=""
 WORKDIR /deployments
 
-ENTRYPOINT exec java $JAVA_OPTS -jar [=AppJar]
+ENTRYPOINT ["java", "-jar", "application.jar"]
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile21.ftl
 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile21.ftl
index 9939f0bba728..f251e591bf5b 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile21.ftl
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile21.ftl
@@ -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.
@@ -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" ]
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile25.ftl
 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile25.ftl
index 506abc971d60..269705fdf7f0 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile25.ftl
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/Dockerfile25.ftl
@@ -35,25 +35,26 @@
 
 ####
 # 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).
+#
 ###
-FROM eclipse-temurin:25-jre-ubi9-minimal
-
-ENV LANGUAGE='en_US:en'
-
-RUN mkdir /deployments
+FROM registry.access.redhat.com/ubi9/openjdk-25: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=""
-WORKDIR /deployments
+ENV JAVA_APP_JAR="/deployments/[=AppJar]"
 
-ENTRYPOINT exec java $JAVA_OPTS -jar [=AppJar]
+ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/main-pom.ftl 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/main-pom.ftl
index 22e99ebf7b79..5d379994932e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/main-pom.ftl
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/main-pom.ftl
@@ -171,6 +171,38 @@
                     </execution>
                 </executions>
             </plugin>
+            <!-- configure thin JAR with classpath manifest for layered Docker 
packaging -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addClasspath>true</addClasspath>
+                            <classpathPrefix>lib/</classpathPrefix>
+                            <mainClass>[=MainClassname]</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <!-- copy dependencies to target/lib for layered Docker packaging 
-->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-dependencies</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            
<outputDirectory>${project.build.directory}/lib</outputDirectory>
+                            <includeScope>runtime</includeScope>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
             <!-- package as runner jar -->
             <plugin>
                 <groupId>org.apache.camel</groupId>
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJibTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJibTest.java
index 79738313ec31..f930c6a6a91a 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJibTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJibTest.java
@@ -84,8 +84,8 @@ class ExportMainJibTest {
                 model.getProperties().getProperty("jib.from.image"));
 
         // should contain jib plugin
-        Assertions.assertEquals(4, model.getBuild().getPlugins().size());
-        Plugin p = model.getBuild().getPlugins().get(3);
+        Assertions.assertEquals(6, model.getBuild().getPlugins().size());
+        Plugin p = model.getBuild().getPlugins().get(5);
         Assertions.assertEquals("com.google.cloud.tools", p.getGroupId());
         Assertions.assertEquals("jib-maven-plugin", p.getArtifactId());
 
@@ -117,8 +117,8 @@ class ExportMainJibTest {
                 model.getProperties().getProperty("jib.from.image"));
 
         // should contain jib plugin
-        Assertions.assertEquals(4, model.getBuild().getPlugins().size());
-        Plugin p = model.getBuild().getPlugins().get(3);
+        Assertions.assertEquals(6, model.getBuild().getPlugins().size());
+        Plugin p = model.getBuild().getPlugins().get(5);
         Assertions.assertEquals("com.google.cloud.tools", p.getGroupId());
         Assertions.assertEquals("jib-maven-plugin", p.getArtifactId());
 
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJkubeTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJkubeTest.java
index 1a53f6dbbc05..b90703c66ddb 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJkubeTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainJkubeTest.java
@@ -84,11 +84,11 @@ class ExportMainJkubeTest {
                 model.getProperties().getProperty("jib.from.image"));
 
         // should contain jib and jkube plugin
-        Assertions.assertEquals(5, model.getBuild().getPlugins().size());
-        Plugin p = model.getBuild().getPlugins().get(3);
+        Assertions.assertEquals(7, model.getBuild().getPlugins().size());
+        Plugin p = model.getBuild().getPlugins().get(5);
         Assertions.assertEquals("com.google.cloud.tools", p.getGroupId());
         Assertions.assertEquals("jib-maven-plugin", p.getArtifactId());
-        p = model.getBuild().getPlugins().get(4);
+        p = model.getBuild().getPlugins().get(6);
         Assertions.assertEquals("org.eclipse.jkube", p.getGroupId());
         Assertions.assertEquals("kubernetes-maven-plugin", p.getArtifactId());
         Assertions.assertEquals("1.19.0", p.getVersion());


Reply via email to