Search code examples
dockerdistroless

Ping distroless Docker image doesn't work


I've created the following Dockerfile:

FROM ubuntu:20.04 as install

RUN apt update && \
    apt -y install iputils-ping

FROM gcr.io/distroless/base-debian11

COPY --from=install /usr/bin/ping ./ping
COPY --from=install /lib/x86_64-linux-gnu/libcap.so.2 /lib/x86_64-linux-gnu/libcap.so.2
COPY --from=install /lib/x86_64-linux-gnu/libidn2.so.0 /lib/x86_64-linux-gnu/libidn2.so.0
COPY --from=install /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libc.so.6
COPY --from=install /lib/x86_64-linux-gnu/libunistring.so.2 /lib/x86_64-linux-gnu/libunistring.so.2
COPY --from=install /usr/lib/x86_64-linux-gnu/libgcrypt.so.20 /usr/lib/x86_64-linux-gnu/libgcrypt.so.20
COPY --from=install /usr/lib/x86_64-linux-gnu/libgpg-error.so.0 /usr/lib/x86_64-linux-gnu/libgpg-error.so.0

ENTRYPOINT ["./ping"]

But I don't understand why it doesn't work. I think that maybe the container stops before the process finishes.

$ docker run --rm distroless-ping 127.0.0.1
$ # no output from the run

At least, if I run it with no arguments I get the output:

$ docker run --rm distroless-ping
./ping: usage error: Destination address required

What's the issue here? I've tried using Docker's CMD instead of ENTRYPOINT but I got the same problem.


Solution

  • I don't know what gcr.io/distroless/base-debian11 is, exactly, but it looks as if it includes an incompatible runtime loader. If we copy the dynamic loader from the Ubuntu image...

    COPY --from=install /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
    

    ...then it seems to work as expected:

    $ docker run -it --rm pingtest 127.0.0.1
    PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
    64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.104 ms
    64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.020 ms
    ^C
    --- 127.0.0.1 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1001ms
    rtt min/avg/max/mdev = 0.020/0.062/0.104/0.042 ms
    

    This makes the final Dockerfile look like:

    FROM ubuntu:20.04 as install
    
    RUN apt update && \
        apt -y install iputils-ping
    
    FROM gcr.io/distroless/base-debian11
    
    COPY --from=install /usr/bin/ping ./ping
    COPY --from=install /lib/x86_64-linux-gnu/libcap.so.2 /lib/x86_64-linux-gnu/libcap.so.2
    COPY --from=install /lib/x86_64-linux-gnu/libidn2.so.0 /lib/x86_64-linux-gnu/libidn2.so.0
    COPY --from=install /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libc.so.6
    COPY --from=install /lib/x86_64-linux-gnu/libunistring.so.2 /lib/x86_64-linux-gnu/libunistring.so.2
    COPY --from=install /usr/lib/x86_64-linux-gnu/libgcrypt.so.20 /usr/lib/x86_64-linux-gnu/libgcrypt.so.20
    COPY --from=install /usr/lib/x86_64-linux-gnu/libgpg-error.so.0 /usr/lib/x86_64-linux-gnu/libgpg-error.so.0
    COPY --from=install /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
    
    ENTRYPOINT ["./ping"]
    

    Note that with one additional library you can build the final image from scratch instead of gcr.io/distroless/base-debian11:

    FROM ubuntu:20.04 as install
    
    RUN apt update && \
        apt -y install iputils-ping
    
    FROM scratch
    
    COPY --from=install /usr/bin/ping ./ping
    COPY --from=install /lib/x86_64-linux-gnu/libcap.so.2 /lib/x86_64-linux-gnu/libcap.so.2
    COPY --from=install /lib/x86_64-linux-gnu/libidn2.so.0 /lib/x86_64-linux-gnu/libidn2.so.0
    COPY --from=install /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libc.so.6
    COPY --from=install /lib/x86_64-linux-gnu/libunistring.so.2 /lib/x86_64-linux-gnu/libunistring.so.2
    COPY --from=install /lib/x86_64-linux-gnu/libgcrypt.so.20 /lib/x86_64-linux-gnu/libgcrypt.so.20
    COPY --from=install /lib/x86_64-linux-gnu/libgpg-error.so.0 /lib/x86_64-linux-gnu/libgpg-error.so.0
    COPY --from=install /lib/x86_64-linux-gnu/libresolv.so.2 /lib/x86_64-linux-gnu/libresolv.so.2
    COPY --from=install /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
    
    ENTRYPOINT ["./ping"]