skip to Main Content

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?

2

Answers


  1. Chosen as BEST ANSWER

    Based on the comments I received, here is an answer for anyone looking to do this with Rust and Alpine.

    As pointed out, the issue comes from trying to use the default x86_64-unknown-linux-gnu to compile the Rust binary. Instead, compile with x86_64-unknown-linux-musl and in particular use:

    rustup target add x86_64-unknown-linux-musl

    Followed by:

    cargo build --release --target=x86_64-unknown-linux-musl

    Then add this new binary to the project instead of the old one, and now Alpine will run it just fine.


  2. 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.
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search