Search code examples
dockerunixrustdockerfilealpine-linux

Why can't an Alpine Linux-based Docker image find commands to execute at an absolute path?


I am new to Docker. I want to containerise a small environment so that I can run executables, but I am stuck because I can't even get an executable to run.

My folder structure looks like this:

example/
|-Dockerfile
|-hello_world

My Dockerfile looks like this:

# Use Alpine Linux as the base image
FROM alpine:latest

# Set the working directory inside the container
WORKDIR /app

# Copy the executable to the container
COPY hello_world /app/

# Set the permissions for the executable
RUN chmod +x /app/hello_world

# Define the command to run your server when the container starts
ENTRYPOINT ["/app/hello_world"]

Then I run:

> sudo docker build -t example .

> sudo docker run --name example_container example

The result of this is this:

exec /app/hello_world: no such file or directory

I have tried as many variations on this as I can think, trying to use CMD, RUN and ENTRYPOINT in the Dockerfile but all have the same result of the image not being able to find the hello_world program in the app folder that exists at the root.

I am really confused because I tried this on my vanilla Ubuntu OS, I put a test folder at the root and then a hello_world in there, and it seemed to work fine that I could run it from wherever with this absolute path.

/app/hello_world is an executable, it's a compiled bit of Rust code. When I run /app/hello_world in the shell on my Ubuntu machine it works fine.

stable-x86_64-unknown-linux-gnu toolchain/rustc 1.71.0

Could someone please tell me what I am doing wrong?


Solution

  • The reason you see the "no such file or directory" error is because the system is looking for the path embedded in the .interp section of the ELF binary. For a binary compiled under glibc, that looks like:

    $ objdump -j .interp -s hello
    
    hello:     file format elf64-x86-64
    
    Contents of section .interp:
     400318 2f6c6962 36342f6c 642d6c69 6e75782d  /lib64/ld-linux-
     400328 7838362d 36342e73 6f2e3200           x86-64.so.2.
    

    In your Alpine image, there is no /lib64/ld-linux-x86-64.so.2, which is what leads to the error message.


    Using a C binary as an example, if I start with:

    #include <stdio.h>
    
    int main() {
        printf("Hello world.\n");
        return 0;
    }
    

    And compile it on my glibc system, then try running it under Alpine, we see:

    $ podman run -it --rm -v $PWD:/src  -w /src alpine
    /src # ./hello
    /bin/sh: ./hello: not found
    

    If we make the expected interpreter available, like this:

    $ podman run -it --rm -v $PWD:/src -w /src \
      -v /lib64/ld-linux-x86-64.so.2:/lib64/ld-linux-x86-64.so.2  alpine
    

    We get a new error:

    /src # ./hello
    ./hello: error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory
    

    If we make the necessary shared library available:

    $ podman run -it --rm -v $PWD:/src -w /src \
      -v /lib64/ld-linux-x86-64.so.2:/lib64/ld-linux-x86-64.so.2 \
      -v /lib64/libc.so.6:/lib64/libc.so.6  alpine
    

    Then the command works as expected:

    /src # ./hello
    Hello world.