The problem is that you build your binary against
glibc (as you are using Ubuntu), but then run it on Alpine (which uses
When you build the binary, some metadata is hardcoded into it, specifically, the interpreter (dynamic linker) location. During the binary execution the kernel uses this interpreter to load the binary and all of its runtime dependencies. When you build against
glibc, the binary requests the
glibc's interpreter (something like
$ readelf -l /bin/uname
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
but there is no such interpreter under Alpine. Alpine has
/lib/ld-musl-x86_64.so.1 instead, and all its binaries are built so that they request exactly this interpreter:
# readelf -l /bin/busybox
[Requesting program interpreter: /lib/ld-musl-x86_64.so.1]
So, when you build your
uname in Ubuntu and then run it in Alpine, the kernel is unable to find the interpreter, thus it returns "not found".
The interesting point is that you may invoke the interpreter manually and this may work if the problem is only in the interpreter:
# /lib/ld-musl-x86_64.so.1 /bin/uname
This is a fake uname
But this, of course, is only for troubleshooting.
So, what to do?
Your options are either statically link your binary (thus making the interpreter and all shared libraries unneeded so that the kernel may load and run the binary on its own):
gcc uname.c -static -o uname
or build it under Alpine (maybe try Docker's multistage builds? I would recommend this approach as in this case you explicitly declare your intention and show that you build your custom binary in Alpine to replace the original Alpine's one).