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

Go & Gradle examples of hot reloading a binary #1244

Closed
wants to merge 1 commit into from
Closed

Conversation

vkorbes
Copy link
Contributor

@vkorbes vkorbes commented Oct 1, 2019

This is a research/discussion branch. Do not merge!

A prospective user messaged us on Slack looking for a workflow that would allow him to re-build Java/Gradle executables on code change, then hot reload them into a running container. He'd like to first deploy this container using Helm.

These are two examples on how to do that. One in Java, as requested, and one in Go. The Helm part is still to be done.

Some details:

  • Both examples have a code exec module, where the source code is, and a container container module, that gets hot-reloaded with the new binary whenever code changes.
  • Inside code, there's a myscript.sh script, which is called by the exec type on code change. This script adds a timestamp to the source code indicating the exact moment when it was called, then builds a binary/artifact, and copies it to the container module.
  • The container module has nothing but that binary/artifact, and on change it hot reloads into the running pod.
  • Inside the pod, entr re-runs it.

About the Go version:

  • Before running, download dependencies with go mod vendor.
  • When the binary runs inside the pod, it outputs how long it took between myscript.sh being called, and the binary being executed (after that it listens on 8080 and does nothing). This is usually 1–4 seconds on my machine. It's worth noting that some large dependencies were added to the binary to simulate a real workload.
  • This feels like a perfectly fine workflow IMHO, and a good start point for a potential Go module type.

About the Java version:

  • First off, I couldn't figure out how to calculate the time difference in Java. So this binary just outputs the Unix time of when myscript.sh was called, not the total between that and being executed like the Go version does.
  • This is where things get weird: At first I used a simple Hello World app that after saying hello, would sleep forever so the container wouldn't die. This sleeping was done with Java internals. Problem is, entr would reload it once, and do nothing on any subsequent changes.
  • I couldn't find a way to fix it, so I made it so that Hello World would say hello and exit, and then used bash to keep the container from dying (by simply calling cat on bash). There's probably something Java-specific that I'm unaware of. As is, it works fine.

Files worth looking:

  • All garden.ymls
  • The Dockerfiles inside the container modules
  • The myscript.sh files in the code modules
  • The source code for the application. That's code/main.go for the Go one, and code/src/main/java/hello/*.java for Java.

IMHO this could serve as a starting point for the Go module type, or for a plugin that does the general "build an artifact then hot reload it."

As @eysi09 mentioned, another solution is to simply have a preSync task on hotReload. That is fine, but sometimes we'll want to have more fine-grained control—e.g. to automatically do the vendoring and whatnot with Go modules—as opposed to a generic type.

So as plugins become a thing users write as opposed to just the core team, something like these examples would be a good template to have.

I'm looking for:

  • Feedback on how to make this more elegant in general. E.g.
  • Feedback on what needs to change for either of these to be worth merging to our examples set.
  • Some light on how to make the container be first deployed using a Helm chart, as the user initially requested—I've never used the Helm type and have no idea how it works.

@przemolb
Copy link

Thanks @ellenkorbes for thorough description. I would decouple the Helm deployment from the rest. In our case we use Helm but others can probably use just kubectl or kustomize or ...
The whole point is that the deployment (as in K8s world deployment) has already been made so the app is already running. This is the initial step which can be done manually.
Now enters the garden which is needed to frequently update a jar in the running pod whenever the code has been modified.

@eysi09
Copy link
Collaborator

eysi09 commented Jan 14, 2020

Closing in favour of #1512.

@eysi09 eysi09 closed this Jan 14, 2020
@thsig thsig deleted the gogradle branch May 9, 2022 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants