3 ms·
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
by KronisLV 4y ago
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 containers and re-used, which would be often if it doesn't change much.
With this setup, deliveries would look a bit like the following:
# SIZE WHAT
1 ~100 MB base OS image (reused if not changed, cached)
2 ~340 MB JDK image (reused if not changed, cached)
3 X MB the app .jar file (changes with every release)
Whereas with the approach in the article, it would look a bit like the following:
# SIZE WHAT
1 ~100 MB base OS image (reused if not changed, cached)
2 Y MB minimal JRE + the app (changes with every release)
For example, consider the example in the article:
36M zulu-hello-jre-linux-x64
338M zulu19.30.11-ca-jdk19.0.1-linux_x64
While it's hard to speak of how any given app would look like if it was just a .jar (or what other real world examples would be like, not just a "Hello world" program), it would only take 10 individual releases to exceed the size of the JDK. In this case, if you deploy once every day, then by the end of the first month, you'd be using ~2X more space for the minimal JRE approach. However, if you would update your JDK version more than once a month, then that might as well go out of the window.
So it appears that it all depends on how much you care about space in the first place, as well as what technologies you use, since the above example only seems relevant for container technologies that have the whole layer mechanism, and only then if you don't squash them for up front space savings for individual container images. On the other hand, if you update your base image and/or the runtime often, then using jlink makes a lot of sense, since the approach with the separate JDK would send the whole thing often anyways.
- chriswarbo 4y agoThose caring about space usage presumably wouldn't include an entire OS in their containers?
- KronisLV 4y agoHmm, 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).
- deno 4y agoYou 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.
- deno 4y agoSeems 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.
- KronisLV 4y ago> 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.