With multistage docker and statically linked binaries you can get damn close to real distroless, meaning an effective FROM scratch
in the final stage.
This is indeed not easy to achieve and usually only seen for rust or golang binaries.
On the other hand side dockerTools
are not perfect with the “runtime dependecy detection”, as nix isn’t.
Using the erlang release system resulted in closures that created wastely large closures as erlang (which gets copied into the release!) got still detected as a runtime dependency, as there was some line in a generated file that referenced the erlang binary used to originally build the release.
In addition to that, the default erlang uses some stuff that is not actually required in docker, like systemd integration for EPMD.
So you need to put some manual effort to reduce the runtime closure, which results in building erlang from source. I was able to place a PR to the related builder before it got integrated into nixpkgs
.
Also erlang modules are by default built with debug enabled, and copied like that, again resulting in references to the closure they are copied from. Those have to be stripped manually. I was able to place a PR that at least gives us an option to stript those after the fact.
It took me some days to analyze this, and fix the issues in the long term.
Though all in all, due to the things mentioned above, there was an overall overhead of ~150 MiB in the runtime closure.
Regular docker builds from a dockerfile wouldn’t have had this problem and an idiomat multistage Dockerfile
usually was less than 50MiB for simple applications.
Achieving the same with nixpkgs’ dockerTools
has been a lot more involved and required knowledge in erlang builds, nixpkgs idioms, the erlang sub ecosystem in nixpkgs, and nix tooling to analyze the issues.
So the docker tools aren’t producing smaller images magically. There might be a lot of effort required to actually get them en par with idiomatic docker files.