[ 
https://issues.apache.org/jira/browse/CAMEL-23601?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Federico Mariani resolved CAMEL-23601.
--------------------------------------
    Resolution: Fixed

> 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
>          Components: camel-jbang
>            Reporter: Federico Mariani
>            Assignee: Federico Mariani
>            Priority: Major
>             Fix For: 4.21.0
>
>
> 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:
> {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