Live data from Hacker News

Using jlink to cross-compile minimal JREs

jakewharton.com

31–40 of 66 posts

Re: Using jlink to cross-compile minimal JREs

#31

It's a pity that system wide JREs are not a thing anymore. I understand that it was difficult to get an updated JRE on the system in the early 2000s, but nowadays almost every computer is online - certainly one where you are currently downloading an application on - and automatic updates are commonplace. You used to be able to just double click on a .jar, and that was a Java application. And it would be trivial engin…

Sounds like https://0install.net which has been around for a while.

Personally I prefer to avoid 'installing' anything: if something's written in Java, its launcher should reference some specific java binary; if something's written in Python, it should reference some specific python3 binary; etc.

For example, my job is mostly writing Scala and building it with Maven; yet I have neither installed system-wide. Instead, they're just dependencies of the build script (along with Bash, etc.).

Re: Using jlink to cross-compile minimal JREs

#32

I wonder how this would play out in a container context, aside from the benefits mentioned in regards to including only what you need and other things like that, but focusing purely on distribution sizes and space reuse. For example, if you would have your application built as a .jar (perhaps with an embedded app server), but use a separate full JDK install, then the latter could be cached on the nodes running the co…

Those caring about space usage presumably wouldn't include an entire OS in their containers?

Re: Using jlink to cross-compile minimal JREs

#33

I wonder how this would play out in a container context, aside from the benefits mentioned in regards to including only what you need and other things like that, but focusing purely on distribution sizes and space reuse. For example, if you would have your application built as a .jar (perhaps with an embedded app server), but use a separate full JDK install, then the latter could be cached on the nodes running the co…

Seems you could also do this:

    # SIZE     WHAT
    1 ~100 MB  Base OS
    2 Y MB     Minimal standalone runtime built with JLink
    3 X MB     App code (not in above image)
Then later you only change #2 if you need more modules or you’re updating the runtime. What makes sense will be situation specific. But presumably if you’re after the security benefits of minimal runtime and don’t want to pay too much premium in storage this is the optimal configuration. Of course doing it this way increases your build complexity somewhat significantly.

Re: Using jlink to cross-compile minimal JREs

#34

I wonder how this would play out in a container context, aside from the benefits mentioned in regards to including only what you need and other things like that, but focusing purely on distribution sizes and space reuse. For example, if you would have your application built as a .jar (perhaps with an embedded app server), but use a separate full JDK install, then the latter could be cached on the nodes running the co…

Those caring about space usage presumably wouldn't include an entire OS in their containers?

Hmm, it depends - sometimes that's a decent tradeoff for development velocity vs distroless containers (from scratch) outside of particular project requirements, in other cases it can just be nice to have some common packages or even tools in your containers, for debugging/troubleshooting, especially if you don't change the base image too often, so it can also benefit from the caching.

As for the (compressed) size of some common base images:

  SIZE   WHAT
  3 MB   alpine:3.17.1
  29 MB  ubuntu:jammy-20221130
  31 MB  debian:stable-20230109-slim
  53 MB  debian:stable-20230109
  32 MB  almalinux:9.1-minimal-20221201
  66 MB  almalinux:9.1-20221201
  44 MB  rockylinux:9.1.20221221-minimal
  61 MB  rockylinux:9.1.20221221
In most cases the OS/userland related layers (which will generally be more cut down than a "full" OS install) will be smaller than the runtimes for languages like Java, .NET, Python, Ruby, Node and so on, though things can get interesting with updates (e.g. slower builds if you cut out package cache in any layer where you need to install software, so it doesn't bloat the layer size, if you need more than one install command per container).

Re: Using jlink to cross-compile minimal JREs

#35

JLink is a pretty nice tool - easy to use and understand, relatively fast, big app size wins. A few misc thoughts: Figuring out what modules you need to ship can be done with the jdeps tool, but, you have to watch out for some gotchas. One is that you have to run it on each JAR or set of jars. It's slow so it helps to do this incrementally. Another is that some critical JVM functions are implemented as 'plugins' that…

Speaking of JVM 'plugins' that are loaded reflectively, don't forget the Java Access Bridge on Windows, as I reported to Hydraulic some months ago. (Fortunately, that one is fixed in Conveyor.)

Re: Using jlink to cross-compile minimal JREs

#36

I wonder how this would play out in a container context, aside from the benefits mentioned in regards to including only what you need and other things like that, but focusing purely on distribution sizes and space reuse. For example, if you would have your application built as a .jar (perhaps with an embedded app server), but use a separate full JDK install, then the latter could be cached on the nodes running the co…

Those caring about space usage presumably wouldn't include an entire OS in their containers?

You include the Base as a layer rather than bundle it so it’s amortized over several releases. Google has a tool to actually bundle your base and cut it down to the very essentials. This is only a thing with Docker and similar. With something like Flatpak it doesn’t even matter if you bundle because OSTree can deduplicate on file level.

Re: Using jlink to cross-compile minimal JREs

#37
post #33

I wonder how this would play out in a container context, aside from the benefits mentioned in regards to including only what you need and other things like that, but focusing purely on distribution sizes and space reuse. For example, if you would have your application built as a .jar (perhaps with an embedded app server), but use a separate full JDK install, then the latter could be cached on the nodes running the co…

Seems you could also do this: # SIZE WHAT 1 ~100 MB Base OS 2 Y MB Minimal standalone runtime built with JLink 3 X MB App code (not in above image) Then later you only change #2 if you need more modules or you’re updating the runtime. What makes sense will be situation specific. But presumably if you’re after the security benefits of minimal runtime and don’t want to pay too much premium in storage this is the optima…

> Then later you only change #2 if you need more modules or you’re updating the runtime.

This is an excellent point, albeit one more thing to think about (which can still be worth it).

> What makes sense seems to be very situation specific.

This is true, honestly the variety of the configurations out there (e.g. dynamic scaling, where the base layers won't benefit from the ability to cache things, or PaaS solutions where nodes might change for different deployments) makes me doubt the usefulness of my post.

Guess that's why there is no one best solution for ALL circumstances.

Re: Using jlink to cross-compile minimal JREs

#38

JLink is a pretty nice tool - easy to use and understand, relatively fast, big app size wins. A few misc thoughts: Figuring out what modules you need to ship can be done with the jdeps tool, but, you have to watch out for some gotchas. One is that you have to run it on each JAR or set of jars. It's slow so it helps to do this incrementally. Another is that some critical JVM functions are implemented as 'plugins' that…

Speaking of JVM 'plugins' that are loaded reflectively, don't forget the Java Access Bridge on Windows, as I reported to Hydraulic some months ago. (Fortunately, that one is fixed in Conveyor.)

Oh yes good point. Thanks for reporting that. The module name is "jdk.accessibility" for anyone jlinking an app that depends on "java.desktop".

Re: Using jlink to cross-compile minimal JREs

#39

Earlier quoted context omitted.

Speaking of JVM 'plugins' that are loaded reflectively, don't forget the Java Access Bridge on Windows, as I reported to Hydraulic some months ago. (Fortunately, that one is fixed in Conveyor.)

Oh yes good point. Thanks for reporting that. The module name is "jdk.accessibility" for anyone jlinking an app that depends on "java.desktop".

BTW, the reason why the Java Access Bridge is a separate thing on Windows, as opposed to AWT just directly implementing the platform accessibility API, is an interesting bit of history. Basically, in the late 90s, Microsoft's accessibility API was way too simplistic. Maybe I can talk about that in some detail if you ever get your podcast going and we talk about accessibility there.
Post reply on HN