GoogleContainerTools / skaffold

Easy and Repeatable Kubernetes Development
https://skaffold.dev/
Apache License 2.0
15.04k stars 1.62k forks source link

Spring Boot DevTools support #2357

Open balopat opened 5 years ago

balopat commented 5 years ago

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 commented 5 years ago

cc @GoogleContainerTools/java-tools

tejal29 commented 5 years ago

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

loosebazooka commented 5 years ago

@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 commented 5 years ago

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

dsyer commented 4 years ago

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 commented 4 years ago

@dsyer this is interesting, I just merged jib support for spring-boot-devtools https://github.com/GoogleContainerTools/skaffold/pull/3382. Are you running package on your own to trigger the rebuild?

dsyer commented 4 years ago

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

loosebazooka commented 4 years ago

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

dsyer commented 4 years ago

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

loosebazooka commented 4 years ago

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

torsten-liermann commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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

torsten-liermann commented 4 years ago

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 commented 4 years ago

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: https://github.com/spring-projects/spring-boot/issues/21424 (more to do with the buildpack than Spring Boot as such).

loosebazooka commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

@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 commented 4 years ago

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 ?

tejal29 commented 3 years ago

Reducing priority since its been an year since last comment.

dsyer commented 3 years ago

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 commented 3 years ago

@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 commented 3 years ago

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 commented 3 years ago

@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 commented 3 years ago

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.