Spring Boot 2.3 introduced a new feature where it is possible to create layered .jar files. This is very useful for docker images layer optimization as described in this blog post: https://spring.io/blog/2020/01/27/creating-docker-images-with-spring-boot-2-3-0-m1?#layered-jars
Unfortunately this doesn't work when generating a war file.
Take this build.gradle
as an example:
plugins {
id 'org.springframework.boot' version '2.3.1.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
id 'war'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '14'
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "Hoxton.SR6")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
bootJar {
layered()
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
test {
useJUnitPlatform()
}
As soon as I add the war
plugin I start to receive the following error when trying to use the layertools:
$ java -Djarmode=layertools -jar build/libs/demo-0.0.1-SNAPSHOT.war list
Unsupported jarmode 'layertools'
Comment From: wilkinsona
Thanks for the suggestion. Why do you want to use a war file rather than a jar file to create a Docker image?
Comment From: RodrigoPetter
Is there anything wrong with using a .war
inside a docker image? Perhaps I am missing some specific knowledge.
Anyway, this is my use case:
I have a webapp with thymeleaf. The following file structure works without any aditional configuration when using the war plugin:
Until today, we alway execute ./gradle bootWar
in ours pipeline, then we put the .war file inside a docker image with the following entrypoint: ENTRYPOINT ["java", "-jar", "/application.war"]
If necessary, I could always download the .war artifact from the pipeline and run it locally.
Since we work with microservice, setting up a development environment can be quite painful, so we use the .jar
and .war
artifacts from the pipelines.
I see two negative points if this layer feature only works with a .jar:
- The artifact from my pipeline will not work since it doesn't contain the files from the webapp folder.
- Additional configurations will be necessary to achieve the same behavior as the war plugin.
Comment From: wilkinsona
Thanks for the additional information. Generally speaking, the only reason to use a .war
file is if you are deploying to a servlet container or you want to use JSPs. When neither of those is the case, we recommend using jar packaging.
From your screenshot above, it looks as if you could switch to .jar
packaging by moving src/main/webapp/assets
to src/main/resources/static/assets
, src/main/webapp/favicon.ico
to src/main/resources/static/favicon.ico
and src/main/webapp/WEB-INF/views
to src/main/resources/templates
.
Comment From: RodrigoPetter
@wilkinsona You are completely right. I made these changes and everything worked as expected (with some adjustments to the thymeleaf settings).
I'm sorry for the inconvenience.
There is even documentation about it here: https://spring.io/guides/gs/serving-web-content/#_add_a_home_page
Comment From: derTobsch
Thanks for the additional information. Generally speaking, the only reason to use a
.war
file is if you are deploying to a servlet container or you want to use JSPs. When neither of those is the case, we recommend using jar packaging.From your screenshot above, it looks as if you could switch to
.jar
packaging by movingsrc/main/webapp/assets
tosrc/main/resources/static/assets
,src/main/webapp/favicon.ico
tosrc/main/resources/static/favicon.ico
andsrc/main/webapp/WEB-INF/views
tosrc/main/resources/templates
.
Sorry for adding a comment into a already closed issue. We have a spring boot 2.3.2 application with jsps and so we have a war packaging. Is it possible to use the build-image goal? That would be a nice feature for us to reduce code and have the benefit of layered docker images until we get rid of the jsps.
Comment From: wilkinsona
Is it possible to use the build-image goal?
Not at the moment, no. Both layering and the build image goal are only supported with jar packaging.
Comment From: dodgex
We are currently migration to Spring Boot 2.3.x and Docker for some of our projects and would love to use the layering to build our docker images.
But as some of our products are deployed to customer servers and some of them have Docker (yet?) we would need to build the project as jar and war. Having just a war that we can deploy in any tomcat and build a layerd Docker image from would be awesome.