我想做一些奇怪的容器,我的任务之一是替换uname
二进制文件。
我编码它:
#include <stdio.h>
int main() {
printf("This is a fake uname\n");
return 0;
}
编译它:
gcc uname.c -o uname
当我在我的 ubuntu 上运行它时它工作正常。
我创建了一个Dockerfile
并将其复制到图像中:
cat > Dockerfile <<EOF
FROM alpine:latest
RUN rm /bin/uname
COPY uname /bin/
ENTRYPOINT sh;
WORKDIR /home
EOF
并建造它docker build -t myimage -f Dockerfile .
当我运行图像时:
docker run -it --rm myimage
该文件存在,但是当我尝试运行它时,它写道它不存在:
/home # uname
sh: uname: not found
/home # ls -lia uname
ls: uname: No such file or directory
/home # ls -lia /bin/uname
35 -rwxr-xr-x 1 root root 8600 Jan 29 13:27 /bin/uname
问题是你构建你的二进制文件
glibc
(因为你使用的是 Ubuntu),然后在 Alpine 上运行它(而musl
不是使用它)。当您构建二进制文件时,一些元数据被硬编码到其中,特别是解释器(动态链接器)位置。在二进制执行期间,内核使用此解释器来加载二进制及其所有运行时依赖项。当您针对 构建时
glibc
,二进制文件会请求 的glibc
解释器(类似于/lib64/ld-linux-x86-64.so.2
):但是Alpine下没有这样的解释器。相反, Alpine 有
/lib/ld-musl-x86_64.so.1
,并且它的所有二进制文件都被构建,以便它们完全请求这个解释器:因此,当您
uname
在 Ubuntu 中构建然后在 Alpine 中运行它时,内核无法找到解释器,因此它返回“未找到”。有趣的是,您可以手动调用解释器,如果问题仅在解释器中,这可能会起作用:
但这当然仅用于故障排除。
那么该怎么办?
您的选择是静态链接您的二进制文件(从而使解释器和所有共享库不再需要,以便内核可以自行加载和运行二进制文件):
或在 Alpine 下构建它(也许尝试 Docker 的多阶段构建?我会推荐这种方法,因为在这种情况下,您明确声明您的意图并表明您在 Alpine 中构建自定义二进制文件以替换原始 Alpine 的二进制文件)。