Eu quero fazer algum container estranho, uma das minhas tarefas era substituir o uname
binário.
Eu codifiquei:
#include <stdio.h>
int main() {
printf("This is a fake uname\n");
return 0;
}
Compilou:
gcc uname.c -o uname
funciona bem quando eu executo no meu Ubuntu.
Eu criei um Dockerfile
e copiei para a imagem:
cat > Dockerfile <<EOF
FROM alpine:latest
RUN rm /bin/uname
COPY uname /bin/
ENTRYPOINT sh;
WORKDIR /home
EOF
E construí-lodocker build -t myimage -f Dockerfile .
quando executo a imagem:
docker run -it --rm myimage
O arquivo existe, mas quando tento executá-lo, ele escreve que não existe:
/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
O problema é que você constrói seu binário
glibc
(já que está usando o Ubuntu), mas depois o executa no Alpine (que usamusl
).Quando você cria o binário, alguns metadados são codificados nele, especificamente, o local do interpretador (vinculador dinâmico). Durante a execução do binário, o kernel usa esse interpretador para carregar o binário e todas as suas dependências de tempo de execução. Quando você constrói contra
glibc
, o binário solicita oglibc
interpretador do (algo como/lib64/ld-linux-x86-64.so.2
):mas não existe tal intérprete sob Alpine. Alpine tem
/lib/ld-musl-x86_64.so.1
, e todos os seus binários são construídos para que eles solicitem exatamente este interpretador:Então, quando você constrói o seu
uname
no Ubuntu e depois o executa no Alpine, o kernel não consegue encontrar o interpretador, então ele retorna " não encontrado ".O interessante é que você pode invocar o interpretador manualmente e isso pode funcionar se o problema for apenas no interpretador:
Mas isso, é claro, é apenas para solução de problemas.
Então o que fazer?
Suas opções são vincular estaticamente seu binário (tornando assim o interpretador e todas as bibliotecas compartilhadas desnecessárias para que o kernel possa carregar e executar o binário por conta própria):
ou construa-o no Alpine (talvez tente as compilações multiestágio do Docker ? Eu recomendaria essa abordagem, pois neste caso você declara explicitamente sua intenção e mostra que constrói seu binário personalizado no Alpine para substituir o do Alpine original).