Search code examples
javamavendockerintellij-ideadcevm

Is it possible to have a "HotReload" docker based java environment?


I am trying to have a java program that is built with maven to run on a docker-compose scenario and hot reload as I make changes. I added trava-jdk libvm on top of the original libvm and added the hotswapagent lib on the proper place. It gives me what I want when I run java -version

Starting HotswapAgent '/usr/local/openjdk-11/lib/hotswap/hotswap-agent.jar'
HOTSWAP AGENT: 10:18:24.771 INFO (org.hotswap.agent.HotswapAgent) - Loading Hotswap agent {1.4.0} - unlimited runtime class redefinition.
HOTSWAP AGENT: 10:18:24.992 INFO (org.hotswap.agent.config.PluginRegistry) - Discovered plugins: [JdkPlugin, Hotswapper, WatchResources, ClassInitPlugin, AnonymousClassPatch, Hibernate, Hibernate3JPA, Hibernate3, Spring, Jersey1, Jersey2, Jetty, Tomcat, ZK, Logback, Log4j2, MyFaces, Mojarra, Omnifaces, ELResolver, WildFlyELResolver, OsgiEquinox, Owb, Proxy, WebObjects, Weld, JBossModules, ResteasyRegistry, Deltaspike, GlassFish, Vaadin, Wicket, CxfJAXRS, FreeMarker, Undertow, MyBatis]
openjdk version "11.0.5" 2019-10-15
OpenJDK Runtime Environment 18.9 (build 11.0.5+10)
Dynamic Code Evolution 64-Bit Server VM 18.9 (build 11.0.5+5-202001261315, mixed mode)

My dockerfile to achieve that is the one below

FROM maven:latest

WORKDIR /tmp
RUN wget https://github.com/TravaOpenJDK/trava-jdk-11-dcevm/releases/download/dcevm-11.0.5%2B5/java11-openjdk-dcevm-linux.tar.gz
RUN tar -xvf  java11-openjdk-dcevm-linux.tar.gz
RUN mv dcevm-11.0.5+5 /dcevm
WORKDIR /dcevm
RUN rm /usr/local/openjdk-11/lib/server/libjvm.so
RUN cp /dcevm/lib/server/libjvm.so /usr/local/openjdk-11/lib/server/
RUN cp -r /dcevm/lib/hotswap /usr/local/openjdk-11/lib/

Now I find myself a little lost on how to apply the hot reload on the Ide and properly run the code.

In case you are wondering why I need such a hack I have an IoT environment that has E2E tests and I wanted to be able to quickly iterate on new tests or failing tests without needing to recompile or restart containers.


Solution

  • I don't have an experience of working with this concrete hotswap agent, but in general to answer your question:

    1. When you build the docker image, you are supposed to run your own application after all (via maven, with java -jar or in any other way) So, When you start the application process, you're supposed to make the application ready for remote debugging:
    -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9999
    
    1. You should expose a debug port in docker so that the IDE will connect to that port on host machine and it will be routed to port 9999 in docker container.

    2. Make sure the application is running

    3. In IDE create "Remote Debug configuration, in IntelliJ: Run/Debug Configurations -> Remote -> create new configuration and specify the host and exposed port that you've created during the step 2. You're supposed to be able to connect and place breakpoints in the code that will interact with IDE

    4. If you do some change in some source file, right click and compile it while you're connected to remote debugging session.

    5. If the change can be done, it will use hotswap at this point and will "upload" the new bytecode to the remote process right inside the docker in this case and will apply this changes without a reload.

    By default JVM already provides Hotspot capabilities, but this library, I believe should provide more flexible/powerful options.