나는 이상한 컨테이너를 만들고 싶은데 내 작업 중 하나는 uname
바이너리를 교체하는 것입니다.
나는 그것을 코딩했다 :
#include <stdio.h>
int main() {
printf("This is a fake uname\n");
return 0;
}
컴파일:
gcc uname.c -o uname
우분투에서 실행하면 잘 작동합니다.
하나를 만들어 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
답변1
문제는 (Ubuntu를 사용하고 있기 때문에) 바이너리를 빌드한 다음 Alpine(Ubuntu를 사용하고 있기 때문에 ) glibc
에서 실행한다는 것입니다.musl
바이너리를 빌드하면 일부 메타데이터가 하드코딩됩니다.통역사(동적 링커) 위치. 바이너리 실행 중에 커널은 이 인터프리터를 사용하여 바이너리와 모든 런타임 종속성을 로드합니다. 인터프리터 에 대해 빌드할 때 glibc
바이너리는 다음을 요청합니다 ( 와 유사 ).glibc
/lib64/ld-linux-x86-64.so.2
$ readelf -l /bin/uname
<...>
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
하지만 알파인에는 그런 통역사가 없습니다. 대신, /lib/ld-musl-x86_64.so.1
Alpine의 모든 바이너리는 이 인터프리터를 요청하도록 구축되었습니다.
# readelf -l /bin/busybox
<...>
[Requesting program interpreter: /lib/ld-musl-x86_64.so.1]
따라서 uname
Ubuntu에서 빌드를 빌드한 다음 Alpine에서 실행하면 커널이 인터프리터를 찾을 수 없으므로 "찾을 수 없음".
흥미롭게도 통역사를 수동으로 호출할 수 있는데, 이것이 문제인 경우 작동할 수 있습니다.오직통역사에서:
# /lib/ld-musl-x86_64.so.1 /bin/uname
This is a fake uname
그러나 이는 물론 문제 해결 목적일 뿐입니다.
그래서 뭐 할까?
옵션은 바이너리를 정적으로 연결하는 것입니다(이렇게 하면 커널이 자체적으로 바이너리를 로드하고 실행할 수 있도록 인터프리터와 모든 공유 라이브러리가 필요하지 않습니다).
gcc uname.c -static -o uname
아니면 Alpine에서 빌드하세요(아마도 Docker의다단계 구축? 이 경우에는 의도를 명확하게 명시하고 원래 Alpine의 바이너리를 대체하기 위해 Alpine에서 사용자 정의 바이너리를 구축하고 있음을 나타내기 때문에 이 접근 방식을 권장합니다.