Federico Mariani created CAMEL-23601:
----------------------------------------

             Summary: camel-jbang - Export container-optimized layered 
packaging for Camel Main and Spring Boot runtimes
                 Key: CAMEL-23601
                 URL: https://issues.apache.org/jira/browse/CAMEL-23601
             Project: Camel
          Issue Type: New Feature
            Reporter: Federico Mariani


h3. Problem

Currently, camel jbang export produces fat JAR deployments for Camel Main and 
Spring Boot runtimes. The generated Dockerfile copies the entire fat JAR as a 
single Docker layer. This means every code change, even a one-line route edit, 
invalidates the entire layer (10-150 MB depending on the number of components), 
forcing a full push/pull of all dependencies on every build.

Quarkus already addresses this via its fast-jar packaging with a 4-layer 
Dockerfile, but Camel Main and Spring Boot are left behind.

This was originally raised by Simon Hartl in [PR 
#21990|https://github.com/apache/camel/pull/21990]:
{quote}
Considering that most exports are destined for containers, would it make sense 
to change how Maven exports are structured? Instead of a Fat JAR, we could 
output a thin JAR with dependencies in a lib folder. This would make container 
layering much more efficient (re-using dependency layers across different 
integrations).
{quote}

h3. Measured gains

I prototyped the layered approach and measured concrete improvements using the 
{{timer-log}} example:

|| Metric || Camel Main || Spring Boot || Quarkus (already done) ||
| Docker layer invalidated on code change (layered) | 5.78 KB | 19.5 KB | ~245 
KB |
| Docker layer invalidated on code change (fat-jar) | 10.8 MB | 21.5 MB | 17.6 
MB |
| Improvement | 1,868x smaller | 1,103x smaller | 72x smaller |
| Docker image size (layered) | 383 MB | 354 MB | 423 MB |
| Docker image size (fat-jar) | 441 MB | 452 MB | 350 MB |
| Image size savings | -58 MB | -98 MB | — |
| Startup time (layered) | 130 ms | 1.06 s | 0.28 s |
| Startup time (fat-jar) | 483 ms | 1.02 s | 0.62 s |
| Startup improvement | 3.7x faster | ~same | 2.2x faster |

With real-world integrations using 50+ Camel components, the dependency layer 
grows to 80-150 MB, making the savings even more significant.

Additionally, multiple routes sharing the same Camel version can share the 
dependency Docker layer across images.

h3. Proposed implementation

Each runtime uses its own native mechanism for layered packaging:

*Spring Boot* — multi-stage Dockerfile with layertools

Spring Boot 2.4+ already produces layered JARs by default. No POM changes 
needed — only the Dockerfile changes to a [multi-stage build using layertools 
extract|https://docs.spring.io/spring-boot/reference/packaging/container-images/efficient-images.html],
 which splits the JAR into 4 layers: dependencies, spring-boot-loader, 
snapshot-dependencies, and application.

The JAR remains a single portable file — layering is only exploited during 
{{docker build}}.

*Camel Main*: thin JAR + lib/ folder alongside the existing fat JAR
  
Add maven-jar-plugin (with classpath manifest) + 
maven-dependency-plugin:copy-dependencies to the generated POM, alongside the 
existing camel-repackager-maven-plugin. This produces both artifacts in target/:

- target/myapp.jar — the fat JAR, same as today (java -jar works anywhere, no 
change for existing users)
- target/myapp.jar.original — the thin JAR (~5 KB) used by the Dockerfile
- target/lib/ — all dependency JARs

The Dockerfile copies lib/ first (cached layer), then the thin .original JAR 
(volatile layer).

The fat JAR remains the primary artifact — users who java -jar locally or 
deploy without containers are unaffected.

{color:red}I am not entirely sure about this approach, we'll end up building a 
layered jar (with its /lib folder) and a fat-jar for backward compatibility, 
the Dockerimage will use only the layered one, but every mvn package will 
generate 2 jars. Any suggestion is welcome{color} [~acosentino] [~davsclaus] 
[~aurelien.pupier] [~gnodet]

*Quarkus*: fast-jar only (already done)

Quarkus fast-jar packaging with 4-layer Dockerfile is already the default since 
CAMEL-23192. The {{--quarkus-package-type}} flag should be deprecated — 
{{uber-jar}} mode produces a broken Dockerfile (references wrong JAR name) and 
is not recommended by Quarkus ([code.quarkus.io|https://code.quarkus.io] does 
not ship an uber-jar Dockerfile).

h3. CLI changes

- Deprecate {{--quarkus-package-type}} (kept for backward compatibility, hidden 
from help).




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to