Description
Spring Boot 2.3 added the ability to supply a layer index file that optimizes the writing of the Spring Boot jar for container use cases. It splits the jar into multiple layers such that the base layers contains the mostly static stuff (dependencies, etc) while the top layer contains the stuff that you change a lot more (the app code). This reduces time to download the image, as the base layers are already cached on your host.
This is important because Spring Boot jars often drag in hundreds of dependency jars. It is not uncommon to have 400MB+ Spring Boot jars. Written as a single layer, a single code line change will require hosts that use the image to pull down a full 400MB again.
Overview: https://spring.io/blog/2020/01/27/creating-docker-images-with-spring-boot-2-3-0-m1
(Unfortunately the code snippets in the article lost their line endings, so the examples are hard to read)
Details:
- https://docs.spring.io/spring-boot/specification/executable-jar/nested-jars.html#appendix.executable-jar.nested-jars.layer-index
- https://docs.spring.io/spring-boot/maven-plugin/packaging.html#packaging.repackage-goal.parameter-details.layers
Exploration:
Explore these features with a simple spring boot app and Maven:
- Generate a spring boot app: initializr Add spring-web and maybe some other dependencies.
- Build the springboot app normally with Maven (no layers) mvn clean install
- Run it locally: java -jar target/myapp.jar
- Create a Dockerfile that launches it in the naive way
- Go back and use the Maven tools to create a layered jar. The doc shows how to do it but I haven't tried it so I am hand waving from here on down...
- Build using Maven.
- Run the app again to show that it still works using java -Djarmode=layertools -jar target/myapp.jar
- Create a Dockerfile that packages up, again using the doc as a guide.
- Prove that you have multiple layers: docker inspect yourimage:latest
- Make a small change to the Spring Boot app code (which is written to the top most layer) and rebuild, only the top layer should have changed. You will see the SHA change in docker inspect.
Implementation:
After we understand the features and options, we can decide how to implement for the Bazel build system. Guessing at the Bazel implementation, I think it will go something like this:
Much like the classpath index file #33, we need to add a springboot() rule attribute (e.g. layer_index_file) so the user can supply the layer index file. I don't think we should do anything magical here (i.e. auto-generating these files). Just allow the user to specify an existing workspace file via the attribute in the rule. This would be optional as the default layout seems sufficient for most use cases. From there, we will have to figure out the fancy work of splitting the written outputs into the layers. From there, we will need to provide examples of rules_oci building the image in layers.
This work may require changing the springboot rule signature in some incompatible way, so assigning to a major release for now.