使用Alpine和Busybox Docker镜像无法运行可执行文件

3

我正在尝试创建一个非常简单的docker镜像,它必须预先安装了lua、luarocks和其他一些可执行文件,下面是dockerfile:

FROM busybox AS builder

WORKDIR /usr/local/bin

# installs curl (reliable alternative to wget)
RUN wget -O curl https://github.com/moparisthebest/static-curl/releases/download/v7.79.1/curl-amd64 && \
    chmod +x curl

# installs luaformatter
RUN wget -O lua-format https://github.com/Koihik/vscode-lua-format/raw/master/bin/linux/lua-format && \
        chmod +x lua-format

# installs stylua
RUN wget -O stylua-0.11.0-linux.zip https://github.com/JohnnyMorganz/StyLua/releases/download/v0.11.0/stylua-0.11.0-linux.zip && \
        unzip stylua-0.11.0-linux.zip && \
        rm stylua-0.11.0-linux.zip && \
        chmod +x stylua

# installs selene
RUN wget -O selene-light-0.14.0-linux.zip https://github.com/Kampfkarren/selene/releases/download/0.14.0/selene-light-0.14.0-linux.zip && \
        unzip selene-light-0.14.0-linux.zip && \
        rm selene-light-0.14.0-linux.zip && \
        chmod +x selene

# installs lua (standalone binary)
RUN curl -k -o lua-5.4.2_Linux54_64_bin.tar.gz -L https://sourceforge.net/projects/luabinaries/files/5.4.2/Tools%20Executables/lua-5.4.2_Linux54_64_bin.tar.gz && \
    tar xvf lua-5.4.2_Linux54_64_bin.tar.gz && \
    mv lua54 lua && \
    rm -rf lua-5.4.2_Linux54_64_bin.tar.gz luac54

# installs luarocks (standalone binary)
RUN wget -O luarocks-3.7.0-linux-x86_64.zip https://luarocks.github.io/luarocks/releases/luarocks-3.7.0-linux-x86_64.zip && \
    unzip luarocks-3.7.0-linux-x86_64.zip && \
    mv luarocks-3.7.0-linux-x86_64/luarocks . && \
    rm -rf luarocks-3.7.0-linux-x86_64*

FROM busybox

COPY --from=builder /usr/local/bin /usr/local/bin

WORKDIR /ataraxis

RUN luarocks install luacheck

CMD stylua lua/ataraxis && \
    lua-format -i lua/ataraxis/*.lua && \
    luacheck --config .luacheckrc lua/ataraxis/*.lua && \
    selene lua/ataraxis

我尝试使用Alpine和Busybox作为Dockerfile的基础镜像,但是无法成功运行这些可执行文件,即使它们位于默认包含在$PATH中的目录(/usr/local/bin),每当我尝试运行其中任何一个时,都会显示以下错误:

$ lua
/bin/sh: lua: not found

我已经搜索并尝试了我能想到的每一个可能的解决方案,但仍然没有运气。


如果您的容器已经启动,请尝试从容器中运行lua安装程序,以更好地了解原因。 - LiquidDeath
2个回答

5

简述:

错误 lua: not found 是动态链接错误的一个症状,在尝试在基于musl-libc的Linux上运行mainland Linux二进制文件(例如Alpine Linux和基于busybox的镜像)时很常见。

要解决此问题,请切换到轻量级的基于glibc的镜像(例如Debian Slim)或在Alpine容器中安装glibc。使BusyBox正常工作不切实际。

详细解释:

一些背景知识。libc,即标准C库,为Linux程序提供C和POSIX API,并是Linux系统的固有部分。 大多数Linux发行版都基于glibc,即GNU C库。 但是,Alpine Linux和BusyBox映像都基于musl标准C库,与glibc通常不兼容。 因此,在基于glibc的发行版(如Ubuntu、Debian或Arch Linux)上构建的可执行文件,在Alpine Linux或BusyBox上不能直接工作。

链接错误是在尝试运行glibc可执行文件时表现出来的。您可以通过将镜像切换到alpine并运行ldd来验证这一点。
/ataraxis # ldd /usr/local/bin/luarocks 
    /lib64/ld-linux-x86-64.so.2 (0x7fbd14310000)
    libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7fbd14310000)
    libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7fbd14310000)
    libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7fbd14310000)
    libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7fbd14310000)
Error relocating /usr/local/bin/luarocks: __fprintf_chk: symbol not found
Error relocating /usr/local/bin/luarocks: makecontext: symbol not found
Error relocating /usr/local/bin/luarocks: setcontext: symbol not found
Error relocating /usr/local/bin/luarocks: __register_atfork: symbol not found
Error relocating /usr/local/bin/luarocks: __strdup: symbol not found
Error relocating /usr/local/bin/luarocks: __libc_alloca_cutoff: symbol not found
Error relocating /usr/local/bin/luarocks: __stpncpy: symbol not found
Error relocating /usr/local/bin/luarocks: __syslog_chk: symbol not found
Error relocating /usr/local/bin/luarocks: getcontext: symbol not found
Error relocating /usr/local/bin/luarocks: __open_2: symbol not found
Error relocating /usr/local/bin/luarocks: errno: symbol not found

使用Alpine Linux的简单且安全的解决方案是使用Alpine包管理器apk安装兼容软件。然而,所需软件在Alpine上可能不存在,或者特定软件版本不可用。在这种情况下,您有两个选择:
  • 使用基于glibc的Docker镜像,例如Debian slim镜像(例如debian:buster-slim - 27MB压缩),而不是Alpine/BusyBox
  • 在基于musl的镜像上安装glibc,使其与glibc程序兼容,但也会大大增加镜像大小。

为什么不使用BusyBox:

BusyBox不适合此自定义。由于它甚至没有包管理器,所有对它的更改和添加都必须手动完成。这肯定是一个极其繁琐且漫长的过程。 Alpine仍然是非常轻量级的镜像,您可以相当简单地安装glibc。

将镜像更新为具有glibc的Alpine:

首先,将busybox替换为Alpine,最好是最新的Alpine发布版alpine:3.14(在第1行和第37行都需要替换)。
其次,在COPY命令之后添加以下行:
ENV GLIBC_REPO=https://github.com/sgerrand/alpine-pkg-glibc
ENV GLIBC_VERSION=2.30-r0
RUN set -ex && \
    apk --update add libstdc++ curl ca-certificates && \
    for pkg in glibc-${GLIBC_VERSION} glibc-bin-${GLIBC_VERSION}; \
        do curl -sSL ${GLIBC_REPO}/releases/download/${GLIBC_VERSION}/${pkg}.apk -o /tmp/${pkg}.apk; done && \
    apk add --allow-untrusted /tmp/*.apk && \
    rm -v /tmp/*.apk && \
    /usr/glibc-compat/sbin/ldconfig /lib /usr/glibc-compat/lib

这将在Alpine容器上安装glibc。最后,运行luarocks
为参考,我已经在pastebin上发布了docker构建输出。

非常感谢,这真的帮了我很多!主要是因为我还在学习Docker。 - henriquehbr
当然,很高兴能够帮忙! - valiano

2

valiano的回答很好地解释了问题。然而,还有另一种解决方案他没有提到,不需要使用glibc:如果你从源代码构建这些程序(无论是在容器中作为构建过程的一部分,还是在任何其他基于musl的环境中),而不仅仅是下载二进制文件,那么它们将在你的容器中正常工作。


只是出于好奇,是否存在某些软件与musl不兼容的情况,需要对其源代码进行更改? - henriquehbr
1
@henriquehbr 是的。请参阅 https://wiki.musl-libc.org/functional-differences-from-glibc.html 了解可能导致不兼容性的一些差异。 - Joseph Sible-Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接