[
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)