Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Spring boot extensions #31

Merged
merged 2 commits into from
Jul 8, 2020
Merged

Add Spring boot extensions #31

merged 2 commits into from
Jul 8, 2020

Conversation

chanseokoh
Copy link
Member

@chanseokoh chanseokoh commented Jun 30, 2020

The extension is to provide better support for GoogleContainerTools/jib#2336 (including and excluding spring-boot-devtools).

Context:
Our preferred way is the user taking care of GoogleContainerTools/jib#2336 themselves by configuring dev and prod profiles to include or exclude spring-boot-devtools in the built image. However, to reduce friction, and considering that Spring Boot has its own mechanism to decide whether to package devtools into their fat JAR, we can write an extension that follows the same logic to decide whether to package devtools into the image. This way, the user will feel the consistent behavior when packaging a fat JAR and an image, while not having to configure profies.

This extension only takes care of the devtools issue for now, but I think we can expand the extension to cover more Spring Boot-specific use-cases if needed.

Gradle:
Before Spring Boot 2.3.0, the user would configure excludeDevtools to control excluding devtools. Starting with 2.3.0, Spring Boot ignores whatever value excludeDevtools has, and the user should explicitly set bootJar.classpath to include developmentOnly dependencies or not. If devtools is on the classpath (or not), it will end up in a fat JAR (or not). What's discouraging is that devtools is always on the classpath before 2.3.0. That is, we should use two separate and incompatible logic for pre-2.3.0 and 2.3.0+. Unfortunately, there doesn't seem to exist a way to get the version of Spring Boot plugin applied. I ended up adding a useDeprecatedExcludeDevtoolsOption property that the use should set to true in pre-2.3.0. 😞

@chanseokoh chanseokoh force-pushed the spring-boot-extensions branch from 8a12e94 to a7d5890 Compare June 30, 2020 21:34
Copy link
Member

@loosebazooka loosebazooka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we handle the jar vs bootjar task situation that is currently handled directly in the jib gradle plugin?

@chanseokoh
Copy link
Member Author

Do you mean potentially moving that special Spring Boot logic into this extension? (I'd like to avoid that, as we've already commited to that.)

If not, I don't think that part affects this extension. That part is about enabling the jar task to use the original JAR, and I think it's independent of reading some values out of bootJar (whether it's enabled or not)?

@celcius112
Copy link

Hello everyone,

Sorry I might be arriving after the war is over, but I think this problem could have a larger solution. Since Spring Boot 2.3 they have added support for layered jars (for gradle and maven). Since Spring boot knows better than us how to package itself effectively, it will not add dev dependencies (such as the devtools) into the bootJar. Unpacking the bootJar will then give us the layers we expect (dependencies, snapshot dep, application, and the spring boot loader) which can effectively be mapped onto the jib layers. The only difference I see with their layering is that they do not layer the application resources.

@chanseokoh
Copy link
Member Author

chanseokoh commented Jul 8, 2020

Hi @celcius112,

Thanks for your feedback and interest! We are aware that Spring Boot started to offer this feature, and potentially we may be able to leverage the information provided by Spring Boot. However, at least for now, we don't have any intention to do so. For complete documentation purposes, I'll list the reasons, so please bear with me:

  • From our perspective, in the context of containerizing a Java app, fundamentally a Spring Boot project is not any different than any other Java apps. Jib can containerize any Java app including a Spring Boot one in the same efficient and optimized way with no Boot-specific code in Jib. I just can't think of a good reason to add a lot of complexity and special code path only to containerize a Boot app in a slightly different and less optimized way (more on the "less optimized" part later); basically, adding unnecessary code to do unnecessary thing is unnecessary. (Sorry for the bad joke.)
  • As of now, Jib doesn't require running the Spring Boot plugin; Jib only requires the user to compile .class files. Not needing to package and then unpack a fat JAR means much faster development iteration and better user experience. This is one of the main selling points of Jib that we think is important and Jib is really good at.
  • To me, I think Jib still does better layering than Spring Boot does:
    • Boot layering doesn't have separate layers for .class and resources files.
    • Boot doesn't have a separate layer for sub-module dependencies in the same multi-module project.
    • Boot creates an unnecessary spring-boot-loader layer (although Jib could just ignore it if it were to leverage Spring Boot's layering).

For the devtools issue where this extension is trying to help people:

Our perspective is that Spring Boot just went out of the Maven/Gradle standards and established their own proprietary convention; for example, their documentation makes people clearly tell Maven that "the devtools dependency is always required and should be available at runtime" while it introduced a Boot-specific switch option that only affects their JAR-repackaging to exclude devtools from their fat JAR even though the Maven system declares that devtools should always be included as a runtime dependency. We think Spring Boot should really fix the root issue (maybe through right documentation); we don't really think Jib should take some action on this front, but since Spring Boot is so wide-spread, we were compelled to find a way to help people anyway. So this is why we decided to help people through an extension instead of doing something in the main Jib code. So, to sum, this extension isn't meant to fix some Jib "issue" (as there's no real issue with Jib from our perspective) but is rather a convenience shortcut that helps people avoid spending their valuable time to set up the devtools dependency in the right way.

In any case, thanks for your feedback! You still make a point that some people may just have a reason to prefer using the Spring-repackaged fat JAR as the source of truth when building an image. We actually had related discussions before and may support that use case eventually (although it would be done in a general way to support any fat JAR instead of a Spring Boot-specific way).

@loosebazooka
Copy link
Member

Ah, didn't realize this was currently just to handle devtools. It might be worth getting back in touch with spring team to see what kind of optimized layering we can do.

@celcius112
Copy link

Thank you @chanseokoh for this thorough and well written explanation ! You've made clear, precise and wise points that have changed my mind :).

We are using Jib with Spring Boot (and JLink, but that's another topic) and are very happy with it. Please continue the good work.

As you say at one point it might be useful to have this kind of capability. One case where I think it might be useful is when defining our own entrypoint. When that happens we need to define ourself the java execution command, something like

# Retrieve the files present in the /app/libs directory before subsequently joining them with a ':'
LIBS=/app/libs/*
exec java  ${JAVA_OPTS} -cp /app/resources:/app/classes:${LIBS/ /:} ${MAIN_CLASS}

In that case I think the spring-boot-loader might do a better job than us, since it will handle the classpath and the main class for us.

Also, although I'm not sure if it's significant, Spring Boot now creates a classpath.idx file providing the ordering that jars should follow when added to the classpath. At one point it might be a good idea to follow what is written in that file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants