Skip to content

Instantly share code, notes, and snippets.

@NobbZ
Created November 20, 2022 16:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NobbZ/1603ba65e135bf293a50c4b98eb41f71 to your computer and use it in GitHub Desktop.
Save NobbZ/1603ba65e135bf293a50c4b98eb41f71 to your computer and use it in GitHub Desktop.
Minimal elixir dockerTools image
pkgs: let
beamPkgs = with pkgs.beam_minimal; packagesWith interpreters.erlangR25;
erlang = beamPkgs.erlang;
elixir = beamPkgs.elixir_1_14;
fetchMixDeps = beamPkgs.fetchMixDeps.override {inherit elixir;};
buildMix' = beamPkgs.buildMix'.override {inherit fetchMixDeps;};
mixRelease = beamPkgs.mixRelease.override {inherit elixir erlang fetchMixDeps;};
in {inherit erlang elixir buildMix' mixRelease fetchMixDeps;}
{
inputs.nixpkgs.url = "github:nixos/nixpkgs?ref=nixpkgs-unstable";
inputs.nobbz.url = "github:nobbz/nixos-config?ref=main";
outputs = {
self,
nixpkgs,
nobbz,
}: let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
npkgs = nobbz.packages.x86_64-linux;
spkgs = self.packages.x86_64-linux;
bpkgs = import ./.nix/beams.nix pkgs;
callPackage = pkgs.lib.callPackageWith (pkgs
// npkgs
// spkgs
// {
inherit callPackage;
inherit (bpkgs) mixRelease fetchMixDeps;
});
in {
inherit (nobbz) formatter;
devShells.x86_64-linux.default = callPackage ./.nix/shell.nix {};
packages.x86_64-linux = {
inherit (bpkgs) erlang elixir;
yamlfmt = callPackage ./.nix/yamlfmt.nix {};
crosslink = callPackage ./.nix/cross_link.nix {};
image = callPackage ./.nix/image.nix {};
};
};
}
{
dockerTools,
crosslink,
}:
dockerTools.buildLayeredImage {
name = "${crosslink.pname}";
tag = "${crosslink.version}";
contents = crosslink;
}
@camelpunch
Copy link

Hey there! I'm on a mission to produce an empty Phoenix project (sans-Ecto) with a docker image of a reasonable size using a flake.

So far I've managed to get to the point where esbuild and tailwind are downloaded and the whole thing produces a docker image that can serve the app and its assets etc. However, the resulting image currently includes 140mb of wx-2.2.2 inside the erlang distribution in the image's nix store. I've attempted to use your examples to override the vanilla nixpkgs erlang and to use the beam_minimal version, but this doesn't seem to take effect.

Can you point me in the right direction? Perhaps I've missed an override in the flake.nix or maybe the wxSupport = false stuff stopped working? I've tried pointing nixpkgs in the flake to master and saw no difference.

@camelpunch
Copy link

An update: I ended up customising the base erlang derivation that elixir depended upon:

    beamPkgs = with pkgs.beam_minimal;
      packagesWith (interpreters.erlangR25.override {
        configureFlags = [
          "--without-wx"
          "--without-et"
          "--without-debugger"
          "--without-observer"
          "--without-termcap"
        ];
        installTargets = ["install"]; # disable documentation, which is ridiculously large, by not doing install-docs
      });

Depending on use case you might still want those apps. Axing the docs makes a massive difference to closure size.

@NobbZ
Copy link
Author

NobbZ commented Jul 20, 2023

beam_minimal.interpreters.erlangR25 (or any other version) should be without wx, there shouldn't be any need to manually override.

@camelpunch
Copy link

camelpunch commented Jul 24, 2023

So in my nixos-unstable experiments, the size of the erlang installations vary pretty wildly. This is important for me as I'm trying to release Phoenix apps with nix using dockerTools directly from a mixRelease.

Size of beam_minimal's erlang: 299M
Size of beam_minimal without install-docs: 99M
Size with the overrides above: 72M

These are the sizes of the /nix/store/*-erlang-25.* dirs with the various overrides settings.

@NobbZ
Copy link
Author

NobbZ commented Aug 2, 2023

I usually do not care for the size of individual folders in the store, but closure sizes only.

Still the mentioned differences make me wonder where and why that is happening and whether this might be a regression.

I am currently trying to check the closure size of the beam_minimal.interpreters.erlang_25, but have to build that one first, which can take up to an hour on my weak machine.

If I can confirm this variancy I will definitely take a closer look into what is going on. The commit linked in the README.md definitely gave me the mentioned closure size of ~60MiB which not only included erlang, but also elixir and my deployment subject (at that point a freshly generated phoenix application).

@NobbZ
Copy link
Author

NobbZ commented Aug 2, 2023

$ nix build nixpkgs\#beam_minimal.interpreters.erlang_25
$ nix path-info ./result -Sh
/nix/store/0b6ywhdaa7q5w7n8xnprl2sy0amgkzpz-erlang-25.3.2.4      337.4M

This is indeed much beyond what I would expect and I will need to bisect that in more detail later today.

@NobbZ
Copy link
Author

NobbZ commented Aug 2, 2023

Oh, wait!

This is as expected!

The "minimal" Erlang is indeed ~300 to 350 MiB in its closure size ("full" is about twice), only the final applications closure will actually benefit from the partially copied OTP. As that then will only copy relevant OTP-apps.

In hindsight, using beam_minimal and beam_nox is not to remove wx, as the application will be built anyway, but no hard linking to the wx libraries happens.

The actual reason for using beam_minimal is to exclude systemd from the closure, which would be kept referenced in the final closure otherwise due to it being "wrapped" into the EPMD for which I have so far not found a way to exclude.

So for checking the size of your deployment, please build the final closure and check its size, not the intermediate erlang artifact, for which we take steps to get rid of it anyway.

If the final closure though still exceeds your expectations, further debugging has to be done on that.

@NobbZ
Copy link
Author

NobbZ commented Aug 2, 2023

And another one: I briefly checked your mix.exs, which loads the :runtime_tools, which again require the :wx application.

Remove that and your final app will not include wx anymore.

@camelpunch
Copy link

Thanks for the advice! Makes sense about the elimination of erlang. I see that the elimination does happen in the closure, but when dockerising I see the erlang stuff return with a vengeance. I'll dig a bit deeper and report!

@NobbZ
Copy link
Author

NobbZ commented Aug 3, 2023

As I have trouble following discussions on a gist, I'd suggest to move any further questions to the official discourse, which I can more actively watch, and where your problem is also more visible to other users.

https://discourse.nixos.org/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment