[Haskell-cafe] Static executables in minimal Docker containers

Vo Minh Thu noteed at gmail.com
Sat Apr 18 09:51:36 UTC 2015


Michael, thanks for solving this !

I wonder how you came up with the need for /lib/ld-linux-x86-64.so.2.
I have needed only /lib64/ld-linux-x86-64.so.2 (which you have too),
so maybe you added it by mistake.

B.t.w, if you don't want to use a Dockerfile, you can do this:

    > tar -C rootfs -c . | docker import - tiny

where rootfs is your repository.

2015-04-14 10:43 GMT+02:00 Michael Snoyman <michael at snoyman.com>:
> Trac ticket created: https://ghc.haskell.org/trac/ghc/ticket/10298#ticket
>
> I've also put together a Docker image called snoyberg/haskell-scratch
> (source at https://github.com/snoyberg/haskell-scratch), which seems to be
> working for me. Here's a minimal test I've put together which seems to be
> succeeding (note that I've also tried some real life programs):
>
> #!/bin/bash
>
> set -e
> set -x
>
> cat > tiny.hs <<EOF
> main :: IO ()
> main = putStrLn "Hello from a tiny Docker image"
> EOF
>
> ghc tiny.hs
> strip tiny
>
> cat > Dockerfile <<EOF
> FROM snoyberg/haskell-scratch
> ADD tiny /tiny
> CMD ["/tiny"]
> EOF
>
> docker build -t tiny .
> docker run --rm tiny
>
>
> On Tue, Apr 14, 2015 at 9:52 AM Michael Snoyman <michael at snoyman.com> wrote:
>>
>> 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
>> complete:
>>
>> /usr/lib/x86_64-linux-gnu/gconv/gconv-modules
>> /usr/lib/x86_64-linux-gnu/gconv/UTF-32.so
>>
>> 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
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>


More information about the Haskell-Cafe mailing list