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

Spring Boot DevTools support #2357

Open
balopat opened this issue Jun 26, 2019 · 28 comments
Open

Spring Boot DevTools support #2357

balopat opened this issue Jun 26, 2019 · 28 comments

Comments

@balopat
Copy link
Contributor

balopat commented Jun 26, 2019

Spring Boot DevTools came up a couple of times as a feature to support for Skaffold's filesync. This requires some more advanced workflows because of syncing compiled files to the container that we could invest into if there is enough demand.

I'm opening this issue to see if there is any interest in this from the user community. If you are a user of both Spring Boot Developer Tools and Skaffold, let us know if you are interested in this feature by commenting or putting a thumbs up on this issue!

@balopat
Copy link
Contributor Author

balopat commented Jun 26, 2019

cc @GoogleContainerTools/java-tools

@priyawadhwa priyawadhwa added the priority/p0 Highest priority. We are actively looking at delivering it. label Aug 20, 2019
@tejal29
Copy link
Member

tejal29 commented Aug 21, 2019

@loosebazooka #1312 is something to consider when designing this.

@loosebazooka
Copy link
Member

loosebazooka commented Aug 21, 2019

@tejal29 is the suggestion that the rebuild happens on the remote machine? instead of building locally and pushing intermediate artifacts over?

I guess we could provide multiple hooking points and see what happens, I'm curious how remote execution would be handled though.

@balopat
Copy link
Contributor Author

balopat commented Aug 21, 2019

interesting suggestion - #1312 would push compilation on the container side - that requires the container to have all the build toolchain. It is similar to what @ahmetb is experimenting with on https://github.com/ahmetb/rundev in a sense that compilation would happen inside the container.

I was primarily thinking that this feature would leverage the developer's machine for compilation, hence compile -> sync compiled files to container -> container server reloads itself instead of sync -> compile inside container -> container server reloads itself

@tejal29 tejal29 added priority/p1 High impact feature/bug. and removed priority/p0 Highest priority. We are actively looking at delivering it. labels Sep 23, 2019
@dsyer
Copy link

dsyer commented Mar 13, 2020

I managed to get Spring Boot devtools to work. You have to be careful to build the image with the devtools dependency included (probably do that in a profile, so the production image is different). If the image is built using the buildpack support in Spring Boot 2.3 it ends up with the app code in /workspace. So this works:

apiVersion: skaffold/v2alpha4
kind: Config
build:
  artifacts:
  - image: localhost:5000/apps/demo
    custom:
      buildCommand: ./mvnw spring-boot:build-image -D docker.image=$IMAGE && docker push $IMAGE
      dependencies:
        paths:
        - pom.xml
        - src/main/resources
        - target/classes
    sync:
      manual:
      - src: "src/main/resources/**/*"
        dest: /workspace/BOOT-INF/classes
        strip: src/main/resources/
      - src: "target/classes/**/*"
        dest: /workspace/BOOT-INF/classes
        strip: target/classes/
deploy:
  kustomize:
    paths: 
    - "src/main/k8s/demo/"

With this builder you have to explicitly ask for devtools to be in the container image, and at the moment we also need to declare that docker.image property explicitly. E.g:

	<properties>
		<docker.image>localhost:5000/apps/${project.artifactId}</docker.image>
	</properties>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludeDevtools>false</excludeDevtools>
					<image>
						<name>${docker.image}</name>
					</image>
				</configuration>
			</plugin>
		</plugins>
	</build>

@loosebazooka
Copy link
Member

@dsyer this is interesting, I just merged jib support for spring-boot-devtools #3382. Are you running package on your own to trigger the rebuild?

@dsyer
Copy link

dsyer commented Mar 13, 2020

Sort of. I’m just making changes the the IDE and they get copied to the target dir, where skaffold notices them.

@loosebazooka
Copy link
Member

Oh right makes sense. So is skaffold watching anything for you?

@dsyer
Copy link

dsyer commented Mar 13, 2020

Yes, I think so. Isn’t that what the sync: config does?

@loosebazooka
Copy link
Member

Yeah, sorry I'm stuck in the jib specific implementation. You're right.

@torsten-liermann
Copy link

torsten-liermann commented Jun 27, 2020

@balopat I'm trying Dave's example with Skaffold 1.12 on Windows. But the $ IMAGE variable is not replaced. Does anything have to be configured for this? Thx.

On Windows, the cmd syntax must be used, i.e.% IMAGE%. Exchanging values via the environment is simple, but as can be seen, incompatible between operating systems. I would prefer to work on Linux, but unfortunately there are situations that do not allow this. :-(

@dsyer buildpacks "starts" a spring boot application via the JarLauncher. Isn't it that devtools doesn't work in this case? The example doesn't work for me.

@loosebazooka
Copy link
Member

If you don't have any special requirements like this, try the springboot devtools example which uses auto sync: https://github.com/GoogleContainerTools/skaffold/tree/master/examples/jib-sync

@torsten-liermann
Copy link

Thanks, I know jib. Your example is not clear. If you change HelloController.java, the entire build will be run.

@torsten-liermann
Copy link

Addendum because I am not allowed to edit my old post: Devtools does not work with webflux, at least as far as the remote update is concerned. issue

@dsyer
Copy link

dsyer commented Jun 29, 2020

I don't think you need remote updates for skaffold though (that's kind of the point of skaffold sync - it handles all of that), so the issue you linked to isn't really relevant. There is another issue that is relevant: spring-projects/spring-boot#21424 (more to do with the buildpack than Spring Boot as such).

@loosebazooka
Copy link
Member

If you change HelloController.java, the entire build will be run.

If you are using maven, this is a problem with maven unfortunately. They don't do incremental builds very well.
Gradle, while it may have its own issues, does the incremental compile much much better.

@dsyer's solution is nice for maven users since the IDE will do the right thing incrementally compiling. Maybe we can improve auto sync to use the outputs from the IDE too.

@chanseokoh
Copy link
Member

@torsten-liermann as @dsyer pointed out, I don't think the remote update feature of Devtools makes sense with Skaffold. You should let Skaffold sync and update files and have Devtools reload them, instead of manually updating server-side files through the remote update of Devtools.

@torsten-liermann
Copy link

@loosebazooka

If you change HelloController.java, the entire build will be run.

If you are using maven, this is a problem with maven unfortunately.

I referred to the configuration of skaffold in the example with maven. It is not necessary for skaffold to start a build if the java code is changed.

@dsyer
Copy link

dsyer commented Jun 29, 2020

Indeed. That's why I used target/classes in the sync configuration. Skaffold will copy the compiled code over if the IDE or command line dumps it in target/classes.

@torsten-liermann
Copy link

@chanseokoh

I don't think the remote update feature of Devtools makes sense with Skaffold. You should let Skaffold sync and update files
and have Devtools reload them, instead of manually updating server-side files through the remote update of Devtools.

I just wanted to mention remote update of Devtools that it doesn't work with webflux apps. I didn't know before. Maybe a bit helpful at the moment: it offers a way to restart the app remotely.
I would like to use buildpacks with skaffold, but as noted by Dave, it doesn't work at the moment.

@Romeh
Copy link

Romeh commented Jul 15, 2020

@balopat i saw the skaffold sample for Spring dev tools , which was quite useful , just small question is it working the same in case of multi module spring boot application ? as i suspect Spring boot dev tools class loader separation (restart and app class loader) will not work in that case as skaffold will sync the modules other than main application as jars in app libs folder not a plain classes as the main module inside the container.

Do we have any example about spring boot multi module app auto sync with skaffold ?

@loosebazooka
Copy link
Member

That's a good question. I haven't really tested the mutlimodule stuff. But as far as general mutlimodule building goes, modules are not included at the class level (*.class) but at a package level (.jar).

Can you confirm it works locally for bootrun ?

@nkubala nkubala added this to the Backlog [P0/P1] milestone Sep 1, 2020
@nkubala nkubala removed this from the Backlog [P0/P1] milestone May 11, 2021
@tejal29 tejal29 added priority/p2 May take a couple of releases and removed priority/p1 High impact feature/bug. labels Jul 1, 2021
@tejal29
Copy link
Member

tejal29 commented Jul 1, 2021

Reducing priority since its been an year since last comment.

@dsyer
Copy link

dsyer commented Jul 2, 2021

That's disappointing, since there is still a problem and an opportunity. Time passing does not really change the priority and almost everything needed is in the thread above (I say "almost" because there is a new feature in Boot that makes it necessary to also add spring.devtools.restart.enabled=true to the system properties). There's a full example here: https://github.com/dsyer/inner-loop-boot-k8s.

@briandealwis
Copy link
Member

@dsyer so it seems like there are several approaches for configuring for a Spring Boot app, and those approaches may need to be periodically updated as Spring Boot changes. Using a custom builder is insufficient as the builders aren't able to configure sync rules or provide dependencies to be monitored.

A user could probably get by with some judicious use of YAML anchors, but that doesn't enable re-use between projects.

@dsyer
Copy link

dsyer commented Jul 6, 2021

Not sure what the several approaches are, or what the differences are between builders and sync rules. A sensible first step would be simply to support Spring Boot where it is now (2.5) by adding a system property. Could it be enabled with a flag in the skaffold.yaml, with a sensible default? I don't know how it works really.

@briandealwis
Copy link
Member

@dsyer your example above uses a custom builder, whereas your inner-loop-boot-k8s example uses buildpacks. I'm surprised that --auto-sync does anything in the buildpacks case as there will be no sync-rules provided in the paketo-built images.

Does this spring.devtools.restart.enabled=true property mean that there is no separate devtools dependency to be included?

@dsyer
Copy link

dsyer commented Jul 7, 2021

Does this spring.devtools.restart.enabled=true property mean that there is no separate devtools dependency to be included?

No, that's in addition, otherwise the launcher detects that it is running a jar file and doesn't include restart.

I'm surprised that --auto-sync does anything in the buildpacks case as there will be no sync-rules provided in the paketo-built images.

I don't think it does (do anything). You have to add sync rules manually in skaffold.yaml. I see that as inconvenient, but not too bad since it doesn't affect the k8s resources that go to production.

As for the custom builder - I only used that in the example above because the buildpacks weren't working at the time. IMO the buildpack is better, but I'm also open to giving people the choice.

The main thing that would help (a lot) in practice is just the system property. If that isn't added by skaffold dev then the user has to add it to the PodSpec, leading to different manifests for dev and prod, and all the awkwardness that entails. There is probably more than one way to solve that problem, but I'm not familiar enough with the internals of skaffold to say what would be best.

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

No branches or pull requests

10 participants