System packages for releases

I did a multistage Docker image today in which you compile a release first, and then copy the binaries into the final image. In development, this application only needs build-essential, ssh, and git, there are no other system dependencies, and production does not need any as far as the application is concerned.

The final image is based on the same official Ubuntu image as the one used in the build Hex image for Elixir.

I believed releases were self-contained, but looks like it is missing something:

/app/erts-10.7.2/bin/beam.smp: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory

I could try to install a package and repeat until the application starts, but would like to know what I am doing and looks to me like an ERTS system dependency is missing (perhaps for the console?).

Are those runtime dependencies documented somewhere?

You need to look at your erlang used to compile the release and make sure that its runtime dependencies are available on the target container.

And releases are not self contained, they just contain the runtime, though not the libraries used by the runtime, those still need to be provided by the host system.

This is why we always say, CPU and OS have to match between host and build system.

The CPU and operating system are the same, this application does not have a binary incompatibility, it is missing a runtime dependency.

The point of releases is that you do not need to have Erlang or Elixir installed in the servers. If you assemble the release in a container of

hexpm/elixir:1.11.0-erlang-23.1-ubuntu-focal-20200703

Then, you copy the release files into an image based on

ubuntu:focal-20200703

However, ERTS seems to have runtime dependencies?

This page documents what’s needed to build Erlang, I am looking for a page that says: “In order to run a release, you need ncurses installed, as well as A, B, and C”.

Again, the runtime dependencies depend on the erlang you used to compile.

If you used a package from your systems pacakge manager, you need to install its dependencies manually, but can drop the actual package.

If though you have a custom build, then the runtime dependencies depend on what build options you have used.

Again, the runtime dependencies depend on the erlang you used to compile.

Sure, but where do I find them documented?

If you used a package from your systems pacakge manager, you need to install its dependencies manually, but can drop the actual package.

Disagree here, Erlang should document its runtime dependencies for releases, the same way it documents its build dependencies.

Again, the point of a release is to not have Erlang installed. Users should not be inspecting package dependencies or peeking at binaries to guess (not know) what is dynamically linked or needed to start a release. You need documentation that says: you need ncurses unless you compiled Erlang with such flag. Something like that.

The runtime dependencies depend on your build configuration.

So only those who built the erlang youu used, can decoument the runtime dependencies.

Though as a rule of thumb, you always need tinfo, as itsd used by the REPL.

You also need the following, depending on how you built:

  • The runtime library of the SSL library used during built, when you built with SSL or crypto support
  • The runtime libaray of the wx version used during build, when you built with wx support
  • The runtime library of the XML library used during build, when you built with XML support
  • The runtime library of the whatever library used during build when you built with whatever support…

Exactly my point when I mentioned flags above.

In my view, Erlang should document: If you compiled with support for X, you need library L at runtime.

Feature X requires libraries and headers available for the build, you require the same libraries (though usually not the headers) available at runtime. There is your list.

This in general is how dynamic linking works.

At least for crypto this is the case: https://erlang.org/doc/man/crypto_app.html

The current crypto implementation uses nifs to interface OpenSSLs crypto library and may work with limited functionality with as old versions as OpenSSL 0.9.8c. FIPS mode support requires at least version 1.0.1 and a FIPS capable OpenSSL installation. We recommend using a version that is officially supported by the OpenSSL project. API compatible backends like LibreSSL should also work.

I’m not sure exactly by what libtinfo is used. Sometimes I have the feeling docker images in a quest to reduce image size tend to remove more and more stuff, which previously where just baseline.

I’m not sure exactly by what libtinfo is used. Sometimes I have the feeling docker images in a quest to reduce image size tend to remove more and more stuff, which previously where just baseline.

I believe it is related to the console, but I had to figure out with a release that did not start. I could install and try until it boots, but that is not a robust procedure.

By now, to play safe I am using the same image I am using to assemble the build, which kind of misses the point.

Hey @fxn,

I think you can check Dockerfile that was used to build Erlang, for your OS this would be https://github.com/hexpm/bob/blob/master/priv/scripts/docker/erlang-ubuntu-focal.dockerfile
Look at the very bottom, where the final image is built. I think it should help, but I don’t know if it’s enough.

Edit: I think it should be okay to reuse the same image as the final one because it doesn’t contain any build artifacts? NVM :man_facepalming:

I guess I am heading to include_erts: false.

The runtime dependencies are unclear. By unclear I mean not clearly documented. Anyone can try to find their way around and figure out what is needed in practice, but I do not like that approach.

Since I am falling back to my build base image

hexpm/elixir:1.11.0-erlang-23.1-ubuntu-focal-20200703

only as a new image with the release copied, the natural option is to opt-out from including ERTS. You have full consistency guaranteed using Docker images, so this approach should work just fine.

As you want to know the runtime dependencies of your Ubuntus erlang, you will need to look at the dependencies of your Ubuntus erlang DEB.

Even if the erlang team would have documented the runtime dependencies of their build properly, that would not hold for a Ubuntu build, as that is customized compared to the canonical build.

Also, in theory, by hitting the right knobs and buttons, you could compile erlang statically linked, basically reducing its actual runtime dependencies to zero…

@NobbZ we will need to agree on disagreeing.

Erlang has to document what it needs to be built, and what it needs to run. The latter may have conditionals, but it has to be there.

Then, you may need to check the conditionals with your package, but the basic information has to be in Erlang docs (like build dependencies are in the Erlang docs, and they have also conditionals).

1 Like

You could also take a look at the Dockerfiles of hex. They already separate building of erlang from the runtime image. So you could use an image, which installs exactly the same as in those highlighted lines, skipping the copy from build.

As you can see there are some dependencies to be installed at runtime as well on top of the base image.

1 Like

Oh sure, but that is the kind of guess work I do not like my production setups to be based on. By using the same base image and not including ERTS I treat this as a black box, whatever runtime dependencies are needed, they figured it out, and when I upgrade, it’s all consistent again even if they changed.