我想做一些奇怪的容器,我的任务之一是替换uname
二进制文件。
我编码它:
#include <stdio.h>
int main() {
printf("This is a fake uname\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译它:
gcc uname.c -o uname
Run Code Online (Sandbox Code Playgroud)
当我在我的 ubuntu 上运行它时它工作正常。
我创建了一个Dockerfile
并将其复制到图像中:
cat > Dockerfile <<EOF
FROM alpine:latest
RUN rm /bin/uname
COPY uname /bin/
ENTRYPOINT sh;
WORKDIR /home
EOF
Run Code Online (Sandbox Code Playgroud)
并建造它 docker build -t myimage -f Dockerfile .
当我运行图像时:
docker run -it --rm myimage
Run Code Online (Sandbox Code Playgroud)
该文件存在,但是当我尝试运行它时,它写入它不存在:
/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
Run Code Online (Sandbox Code Playgroud)
问题是您针对glibc
(因为您使用的是 Ubuntu)构建二进制文件,然后在 Alpine 上运行它(musl
改为使用)。
当您构建二进制文件时,一些元数据被硬编码到其中,特别是解释器(动态链接器)位置。在二进制执行期间,内核使用此解释器加载二进制文件及其所有运行时依赖项。当您针对 构建时glibc
,二进制文件会请求glibc
的解释器(类似于/lib64/ld-linux-x86-64.so.2
):
$ readelf -l /bin/uname
<...>
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
Run Code Online (Sandbox Code Playgroud)
但是Alpine下没有这样的解释器。/lib/ld-musl-x86_64.so.1
相反,Alpine 已经构建了它的所有二进制文件,以便它们准确地请求这个解释器:
# readelf -l /bin/busybox
<...>
[Requesting program interpreter: /lib/ld-musl-x86_64.so.1]
Run Code Online (Sandbox Code Playgroud)
因此,当您uname
在 Ubuntu 中构建并在 Alpine 中运行它时,内核无法找到解释器,因此它返回“未找到”。
有趣的一点是,您可以手动调用解释器,如果问题仅出现在解释器中,这可能会起作用:
# /lib/ld-musl-x86_64.so.1 /bin/uname
This is a fake uname
Run Code Online (Sandbox Code Playgroud)
但这当然仅用于故障排除。
那么该怎么办?
您的选择是静态链接您的二进制文件(因此不需要解释器和所有共享库,以便内核可以自行加载和运行二进制文件):
gcc uname.c -static -o uname
Run Code Online (Sandbox Code Playgroud)
或在 Alpine 下构建它(也许尝试 Docker 的多阶段构建?我会推荐这种方法,因为在这种情况下,您明确声明了您的意图并表明您在 Alpine 中构建了自定义二进制文件以替换原始的 Alpine 二进制文件)。
归档时间: |
|
查看次数: |
1120 次 |
最近记录: |