[Haskell-cafe] Static executables in minimal Docker containers

Michael Snoyman michael at snoyman.com
Tue Apr 14 06:52:51 UTC 2015

Actually, I seem to have found the problem:

open("/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache", O_RDONLY) = -1
ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/gconv/gconv-modules", O_RDONLY|O_CLOEXEC) =
-1 ENOENT (No such file or directory)

I found that I needed to copy over the following files to make my program


Once I did that, I could get the executable to run in the chroot. However,
even running the statically linked executable still required most of the
shared libraries to be present inside the chroot. So it seems that:

* We can come up with a list of a few files that need to be present inside
a Docker image to provide for minimal GHC-compiled executables
* There's a bug in the RTS that results in an infinite loop

I'm going to try to put together a semi-robust solution for the first
problem, and I'll report the RTS issue on Trac.

On Tue, Apr 14, 2015 at 9:25 AM Michael Snoyman <michael at snoyman.com> wrote:

> I have a bit more information about this. In particular: I'm able to
> reproduce this using chroot (no Docker required), and it's reproducing with
> a dynamically linked executable too. Steps I used to reproduce:
> 1. Write a minimal "foo.hs" containing `main = putStrLn "Hello World"`
> 2. Compile that executable and put it in an empty directory
> 3. Run `ldd` on it and copy all necessary libraries inside that directory
> 4. Run `sudo strace -o log.txt . /foo`
> I've uploaded the logs to:
> https://gist.github.com/snoyberg/095efb17e36acc1d6360
> Note that, due to size of the output, I killed the process just a few
> seconds after starting it, but when I let the output run much longer, I
> didn't see any difference in the results. I'll continue poking at this a
> bit, but most likely I'll open a GHC Trac ticket about it later today.
> On Tue, Apr 14, 2015 at 12:39 AM Albert Y. C. Lai <trebla at vex.net> wrote:
>> I wonder whether you already know the following, and whether it is
>> relevant to begin with. (Plus, my knowledge is fairly sketchy.)
>> Even though you statically link glibc, its code will, at run time,
>> dlopen a certain part of glibc.
>> Why: To provide a really uniform abstraction layer over user account
>> queries, e.g., man 3 getpwnam, regardless of whether the accounts are
>> from /etc/passwd, LDAP, or whatever.
>> Therefore, during run time, glibc first reads some config files of the
>> host to see what kind of user account database the host uses. If it's
>> /etc/passwd, then dlopen the implementation of getpwnam and friends for
>> /etc/passwd; else, if it's LDAP, then dlopen the implementation of
>> getpwnam and friends for LDAP; etc etc.
>> So that later when you call getpwnam, it will happen to "do the right
>> thing".
>> This demands the required *.so files to be accessible during run time.
>> Moreoever, if you statically link glibc, this also demands the required
>> *.so files to version-match the glibc you statically link.
>> (It is the main reason why most people give up on statically linking
>> glibc.)
>> _______________________________________________
>> Haskell-Cafe mailing list
>> Haskell-Cafe at haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20150414/c6b74664/attachment.html>

More information about the Haskell-Cafe mailing list