Erlang and Docker - Part 1 - Part 1 doesn't need a subtitle

See part 0 here on why I decided to do this.
This blog post assumes that you already have some familiarity with Erlang/OTP and Docker.
To follow this article, clone cowdock.

First, make sure that everything works, build the release with:

make
make release

Try running the release with _rel/cowdock/bin/cowdock foreground and point your browser to http://localhost:8080.
Now that we have created a release, the next step is to figure out its runtime dependencies.
For that, we use ldd:

Hmm, linux-vdso.so, libdl.so, libpthread.so… nothing unusual here, all are provided by the glibc package 1.
Two entries stand out: libz.so.1 and libncursesw.so. The former is zlib and is used for compression.
I don’t think it is optional.
stdlib has a zip module which is loaded on start-up.
release_handler has a function called untar_release.
However, a quick search for “erlang zlib” gives us a link to the build instruction page, which contains:

–{enable,disable}-builtin-zlib - Use the built-in source for zlib.

This means Erlang can be built with zlib statically linked.
Similarly, searching for “erlang ncurses” gives a link to the mailing list, which contains:

Erlang uses ncurses in the terminal driver for the so called new shell.
http://github.com/erlang/otp/blob/pu/erts/emulator/drivers/unix/ttsl_drv.c

It is also possible to build an Erlang ersion which does not use
term_cap with the configure option

Some of the available configure options are:

–{with,without}-termcap: termcap (without implies that only the old
Erlang shell can be used)

This means we can totally get rid of ncurses2.
However, building Erlang is a tedious task.
And then there’s also a problem with having multiple versions on the same machine.
Luckily, a fine gentleman has created erln8.
It’s a tool which helps building Erlang with different configuration and easily switching between different versions.
Let’s setup erln8:

# If you have Erlang in /usr/local/bin, this will overwrite it
git clone https://github.com/metadave/erln8.git
cd erln8
make
sudo make install
# Initial setup
erln8 --init
erln8 --clone default

To setup erln8 to build our customized Erlang version, open ~/.erln8.d/config in a text editor and add the following ridiculously long line under the [Configs] section:

--without-termcap get rids of the ncurses dependency.
--enable-builtin-zlib get rid of zlib dependency.
Other than that, other applications are disabled to save build time and they are not needed for this example.
You can always build a more completed version if needed.
Let’s build this customized and stripped down version:

erln8 --build--tag OTP-17.1.2 --id OTP-17.1.2-min --config=min

Now is the time for a commercial break. stay tune, we’ll be back after it finishes building.

To config erln8 to use this version, all we need is an erln8.config file with the following content:

[Config]
Erlang=OTP-17.1.2-min

Everytime we cd into that folder or its subfolder, erl will invoke the corresponding version.
Let’s rebuild the release:

Yep, they’re gone.
Let’s get to the main part: building a docker base image and our app image.

ArchLinux includes a program called pacstrap which allows one to create a base installation of ArchLinux in another mounted device or folder 3.
This is perfect! pacstrap is provided with the arch-install-scripts package.
Let’s go through the package that we need:

Erlang uses shell script for its boot up sequence so we need a shell and some common utilities like basename, which…
Those are quite heavy so let’s use busybox instead.

glibc since the emulator is written in C after all.

openssl: crypto depends on it and cowboy depends on crypto and we are using cowboy.
It’s not listed by ldd because it’s loaded dynamically when crypto starts.
It’s not a dependency of the runtime system anyway.

It could be smaller if we are more aggressive in deleting libraries in /usr/lib but I’m playing safe here.
For now, it’s close enough to being small.
All that’s left is to build a docker image with some automation.

release.tar.gz is a compressed archive of our release.
Building the image is done in a separate sub-folder with compressed files to minimize the amount of data sent to the daemon and save time.
The whole process is automated using the following make rules: