【问题标题】:Docker Alpine executable binary not found even if in PATH即使在 PATH 中也找不到 Docker Alpine 可执行二进制文件
【发布时间】:2022-02-23 11:43:26
【问题描述】:

我有一个高山运行容器,其中包含usr/local/bin 中的一些二进制文件

当我lsusr/local/bin 的内容时,我得到了这个输出:

/usr/local/bin # ls
dwg2SVG     dwg2dxf     dwgadd      dwgbmp      dwgfilter   dwggrep     dwglayers   dwgread     dwgrewrite  dwgwrite    dxf2dwg     dxfwrite

这是我所期望的。 但是,如果我通过调用它来执行其中一个二进制文件,我会从 shell 收到 not found 错误:

/usr/local/bin # dwg2dxf
sh: dwgread: not found
/usr/local/bin # ./dwg2dxf
sh: ./dwgread: not found

我测试了我的$PATH,这似乎是正确的:

/usr/local/bin # echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

如何使这些二进制文件可调用或“可创建”?我是否错过了 Dockerfile 构建中的某些内容? 我想 alpine 中的 ldconfig 命令出了点问题,但我不确定。

编辑

正如这里的一个答案所建议的,我执行了file 命令,这是输出:

/usr/local/bin # file dwg2dxf
dwgread: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=7835d4a42651a5fb7bdfa2bd8a76e40096bacb07, with debug_info, not stripped

这些二进制文件来自LibreDWG Official repository 以及我的 Dockerfile 的第一部分。这是完整的 Dockerfile:

# podman/docker build -t libredwg .
############################
# STEP 1 build package from latest tar.xz
############################

FROM python:3.7.7-buster AS extracting
# libxml2-dev is broken so we need to compile it by our own
ARG LIBXML2VER=2.9.9
RUN apt-get update && \
    apt-get install -y --no-install-recommends autoconf libtool swig texinfo \
            build-essential gcc libxml2 python3-libxml2 libpcre2-dev libpcre2-32-0 curl \
            libperl-dev libxml2-dev && \
    mkdir libxmlInstall && cd libxmlInstall && \
    wget ftp://xmlsoft.org/libxml2/libxml2-$LIBXML2VER.tar.gz && \
    tar xf libxml2-$LIBXML2VER.tar.gz && \
    cd libxml2-$LIBXML2VER/ && \
    ./configure && \
    make && \
    make install && \
    cd /libxmlInstall && \
    rm -rf gg libxml2-$LIBXML2VER.tar.gz libxml2-$LIBXML2VER
WORKDIR /app
RUN tarxz=`curl --silent 'https://ftp.gnu.org/gnu/libredwg/?C=M;O=D' | grep '.tar.xz<' | \
         head -n1|sed -E 's/.*href="([^"]+)".*/\1/'`; \
    echo "latest release $tarxz"; \
    curl --silent --output "$tarxz" https://ftp.gnu.org/gnu/libredwg/$tarxz && \
    mkdir libredwg && \
    tar -C libredwg --xz --strip-components 1 -xf "$tarxz" && \
    rm "$tarxz" && \
    cd libredwg && \
    ./configure --disable-bindings --enable-release && \
    make -j `nproc` && \
    mkdir install && \
    make install DESTDIR="$PWD/install" && \
    make check DOCKER=1 DESTDIR="$PWD/install"

############################
# STEP 2 install into stable-slim
############################

# pull official base image
FROM osgeo/gdal:alpine-normal-latest

# set work directory
WORKDIR /usr/src/app



# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# copy requirements file
COPY ./requirements.txt /usr/src/app/requirements.txt

# install dependencies
RUN set -eux \
    && apk add --no-cache --virtual .build-deps build-base \
        py3-pip libressl-dev libffi-dev gcc musl-dev python3-dev postgresql-dev\
    && pip3 install --upgrade pip setuptools wheel \
    && pip3 install -r /usr/src/app/requirements.txt \
    && rm -rf /root/.cache/pip

# Install libredwg binaries
COPY --from=extracting /app/libredwg/install/usr/local/bin/* /usr/local/bin/
COPY --from=extracting /app/libredwg/install/usr/local/include/* /usr/local/include/
COPY --from=extracting /app/libredwg/install/usr/local/lib/* /usr/local/lib/
COPY --from=extracting /app/libredwg/install/usr/local/share/* /usr/local/share/
RUN ldconfig /usr/local/bin/
RUN ldconfig /usr/local/include/
RUN ldconfig /usr/local/lib/
RUN ldconfig /usr/local/share/

# copy project
COPY . /usr/src/app/

【问题讨论】:

  • 如果您尝试使用绝对路径执行它会怎样?:/usr/local/bin/dwg2dxf 另外,$PATH 是否导出以便dwg2dxf 也看到它,因为错误是dwgread: not found 就像@987654338 @ 找不到要执行的 dwgread
  • @jossefaz :我注意到您的问题中有两件奇怪的事情:首先您将其标记为 bash,但您收到的错误消息并非来自 bash。您不会测试与您执行的命令相关的 PATH 。为了安全起见,我会做一个(printenv PATH; ls -l /usr/local/bin/dwg2dxf; dwg2dxf)
  • @user1934428 :我更新了问题标签。对于第二点,我将尝试使用输出编辑 ;y 问题。但我认为通过在我的 dockerfile 中使用另一个基本映像,我已经接近解决方法......
  • 您能否编辑问题以直接包含 Dockerfile,而不是在链接后面?二进制文件来自哪里?切换到 Ubuntu 基础可能会解决此类问题,或者您可能缺少一些需要安装的共享库依赖项。
  • @DavidMaze :感谢您的评论。我已经编辑了我的问题整个 Dockefile 以及这些二进制文件来自的官方存储库的链接。实际上,我在一小时前确实更改了基本图像并且它起作用了。但这对我来说不是一个理想的解决方案。但是由于它有效并且可以帮助其他人,所以我发布了这个解决方法作为对我自己问题的回应......如果有人发现这个解决方法有任何改进,请随时发布另一个答案,我可以删除我的

标签: linux docker shell alpine


【解决方案1】:

在 Alpine Linux 上,not found 错误是动态链接故障的典型症状。 musl 的ldd 链接器确实是一个相当混乱的错误。

世界上大多数 Linux 软件都链接到glibc,即 GNU libc 库(libc 提供标准 C 库和 POSIX API)。大多数 Linux 发行版都基于 glibc。 OTOH,Alpine Linux 基于musl libc 库,这是一个最小实现并且严格符合 POSIX。例如,基于 glibc 发行版构建的可执行文件依赖于 /lib/x86_64-linux-gnu/libc.so.6,这在 Alpine 上不可用(除非它们是静态链接的)。

除了这种依赖关系,重要的是要注意,虽然 musl 试图在一定程度上保持 glibc 兼容性,但它远未完全兼容,并且针对 glibc 构建的复杂软件无法与 musl-libc 一起使用,所以简单地说将 /lib/ld-musl-x86_64.so.1 符号链接到 glibc 路径不太可能。

一般来说,有几种方法可以在 Alpine 上运行 glibc 二进制文件:

  1. 安装一个 glibc 兼容包,libc6-compatgcompat
# apk add gcompat
apk add libc6-compat

这两个包都提供了一个轻量级的 glibc 兼容层,它可能适合运行简单的 glibc 应用程序。 libc6-compat 实现 glibc 兼容性 API,并提供到 glibc 共享库的符号链接,例如 libm.solibpthread.solibcrypt.sogcompat 软件包基于 Adelie Linux gcompat project 并执行相同的操作,但提供了单个库 libgcompat.so。这两个库都安装了加载程序存根。取决于应用程序,其中一个可能有效,而另一个无效,因此最好同时尝试。

  1. 在 Alpine 上安装正确的 glibc,以提供所有 glibc 方法和功能。有可用于 Alpine 的 glibc 构建,应按以下过程安装(示例):
# Source: https://github.com/anapsix/docker-alpine-java

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
  1. 使用静态链接的可执行文件。静态可执行文件不携带动态依赖项,可以在任何 Linux 上运行。

  2. 或者,该软件可以从 Alpine 上的源代码构建。

对于LibreDWG,我们先来验证一下问题:

/usr/local/bin # ./dwg2dxf
/bin/sh: ./dwg2dxf: not found
/usr/local/bin
/usr/local/bin # ldd ./dwg2dxf
    /lib64/ld-linux-x86-64.so.2 (0x7fd375538000)
    libredwg.so.0 => /usr/local/lib/libredwg.so.0 (0x7fd3744db000)
    libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7fd375538000)
    libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7fd375538000)
Error relocating /usr/local/lib/libredwg.so.0: __strcat_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __snprintf_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __memcpy_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __stpcpy_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __strcpy_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __printf_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __fprintf_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __strncat_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __sprintf_chk: symbol not found
Error relocating ./dwg2dxf: __snprintf_chk: symbol not found
Error relocating ./dwg2dxf: __printf_chk: symbol not found
Error relocating ./dwg2dxf: __fprintf_chk: symbol not found

您可以看到dwg2dxf 依赖于几个glibc 符号。 现在,让我们按照选项 2 安装 glibc:

/usr/src/app # cd /usr/local/bin
/usr/local/bin # ls
dwg2SVG     dwg2dxf     dwgadd      dwgbmp      dwgfilter   dwggrep     dwglayers   dwgread     dwgrewrite  dwgwrite    dxf2dwg     dxfwrite
/usr/local/bin # ./dwg2dxf
/bin/sh: ./dwg2dxf: not found
/usr/local/bin # export GLIBC_REPO=https://github.com/sgerrand/alpine-pkg-glibc && \
> export GLIBC_VERSION=2.30-r0 && \
> 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
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/community/x86_64/APKINDEX.tar.gz
(1/1) Installing curl (7.74.0-r1)
Executing busybox-1.32.1-r3.trigger
OK: 629 MiB in 126 packages
(1/2) Installing glibc (2.30-r0)
(2/2) Installing glibc-bin (2.30-r0)
Executing glibc-bin-2.30-r0.trigger
/usr/glibc-compat/sbin/ldconfig: /usr/local/lib/libredwg.so.0 is not a symbolic link
/usr/glibc-compat/sbin/ldconfig: /usr/glibc-compat/lib/ld-linux-x86-64.so.2 is not a symbolic link
OK: 640 MiB in 128 packages
removed '/tmp/glibc-2.30-r0.apk'
removed '/tmp/glibc-bin-2.30-r0.apk'
/usr/glibc-compat/sbin/ldconfig: /usr/glibc-compat/lib/ld-linux-x86-64.so.2 is not a symbolic link

/usr/glibc-compat/sbin/ldconfig: /usr/local/lib/libredwg.so.0 is not a symbolic link

瞧:

/usr/local/bin # ./dwg2dxf

Usage: dwg2dxf [-v[N]] [--as rNNNN] [-m|--minimal] [-b|--binary] DWGFILES...

【讨论】:

  • 那么最后,“未找到”是指链接器尝试但未能找到的符号吗?
  • @Charley 实际上是因为链接器未能找到整个 glibc 共享对象 /lib64/ld-linux-x86-64.so.2。在 glibc 安装过程中,库安装在/usr/glibc-compat/lib/ld-linux-x86-64.so.2,然后符号链接到 lib64 位置。
  • 我在构建一个简单的 Go / Golang 程序后遇到了这个问题。使用以下选项来构建 Go 应用程序有帮助:CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo src/main.go。也许并非所有这些都是必要的。我在这里找到了这个解决方案:callicoder.com/docker-golang-image-container-example
  • 谢谢先生! 2号在我的情况下有效:)
【解决方案2】:

试试apk add gcompat (https://pkgs.alpinelinux.org/package/edge/community/x86/gcompat)。

gcompat 提供/lib64/ld-linux-x86-64.so.2/lib/ld-linux-x86-64.so.2 (https://pkgs.alpinelinux.org/contents?file=ld-linux-x86-64.so.2)。

【讨论】:

  • 只需将 gcompat 添加到 apk 添加列表并为我工作。谢谢
【解决方案3】:

编辑:

如需完整解决方案,请参阅@valiano'response

这只是我在阅读@valiano'response之前发现的一种解决方法

解决方法

我通过切换到另一个基本映像(基于 Ubuntu)找到了解决方法 这是新的工作 Dockerfile:

# podman/docker build -t libredwg .
############################
# STEP 1 build package from latest tar.xz
############################

FROM python:3.7.7-buster AS extracting
# libxml2-dev is broken so we need to compile it by our own
ARG LIBXML2VER=2.9.9
RUN apt-get update && \
    apt-get install -y --no-install-recommends autoconf libtool swig texinfo \
            build-essential gcc libxml2 python3-libxml2 libpcre2-dev libpcre2-32-0 curl \
            libperl-dev libxml2-dev && \
    mkdir libxmlInstall && cd libxmlInstall && \
    wget ftp://xmlsoft.org/libxml2/libxml2-$LIBXML2VER.tar.gz && \
    tar xf libxml2-$LIBXML2VER.tar.gz && \
    cd libxml2-$LIBXML2VER/ && \
    ./configure && \
    make && \
    make install && \
    cd /libxmlInstall && \
    rm -rf gg libxml2-$LIBXML2VER.tar.gz libxml2-$LIBXML2VER
WORKDIR /app
RUN tarxz=`curl --silent 'https://ftp.gnu.org/gnu/libredwg/?C=M;O=D' | grep '.tar.xz<' | \
         head -n1|sed -E 's/.*href="([^"]+)".*/\1/'`; \
    echo "latest release $tarxz"; \
    curl --silent --output "$tarxz" https://ftp.gnu.org/gnu/libredwg/$tarxz && \
    mkdir libredwg && \
    tar -C libredwg --xz --strip-components 1 -xf "$tarxz" && \
    rm "$tarxz" && \
    cd libredwg && \
    ./configure --disable-bindings --enable-release && \
    make -j `nproc` && \
    mkdir install && \
    make install DESTDIR="$PWD/install" && \
    make check DOCKER=1 DESTDIR="$PWD/install"

############################
# STEP 2 install into stable-slim
############################

# pull official base image
FROM osgeo/gdal:ubuntu-small-latest

# set work directory
WORKDIR /usr/src/app



# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# copy requirements file
COPY ./requirements.txt /usr/src/app/requirements.txt

# install dependencies
RUN set -eux \
    && apt-get update && apt-get install -y --no-install-recommends build-essential \
        libc6 python3-pip libffi-dev musl-dev gcc python3-dev postgresql-server-dev-all\
    && pip3 install --upgrade pip setuptools wheel \
    && pip3 install -r /usr/src/app/requirements.txt \
    && rm -rf /root/.cache/pip

# Install libredwg binaries
COPY --from=extracting /app/libredwg/install/usr/local/bin/* /usr/local/bin/
COPY --from=extracting /app/libredwg/install/usr/local/include/* /usr/local/include/
COPY --from=extracting /app/libredwg/install/usr/local/lib/* /usr/local/lib/
COPY --from=extracting /app/libredwg/install/usr/local/share/* /usr/local/share/
RUN ldconfig

# copy project
COPY . /usr/src/app/

基本上我只是改变了

FROM osgeo/gdal:alpine-normal-latest

FROM osgeo/gdal:ubuntu-small-latest

我也更新了依赖项安装(从apk add alpine PM 切换到apt-get

这对我来说不是一个理想的解决方案,因为使用基于 alpine 的图像会生成更轻量级的容器,但它可以正常工作,因此我将其发布为可能的解决方案。

@valiano'response最佳解决方案。如果您关心轻量级图像,请参考它。

【讨论】:

    【解决方案4】:

    它可能不是您可以在相关系统上使用的二进制格式。检查您的架构和文件格式(例如使用file 命令)。

    编辑: /lib64/ld-linux-x86-64.so.2 存在吗?可以运行吗?

    进一步编辑: 这里的一般想法是动态链接的二进制文件可以被认为是带有解释器的脚本。请参阅此LWN article 了解更多详细信息,以了解此处可能发生的情况。如果您的二进制文件适用于错误的平台,您将需要新的二进制文件,或者您需要在正确的平台上运行它们。

    您可以检查的另一件事是,此二进制文件的file 输出是否与正常工作的二进制文件file 的输出不同(例如/bin/ls)。

    【讨论】:

    • 您好,感谢您的回答。我将file 命令的输出添加到我的问题中。我不是操作系统大师,但我在输出中看不到任何与我使用的 alpine 图像不兼容的内容...也许您可以在这里看到任何兼容性问题?
    • 你说得对...解释器/lib64/ld-linux-x86-64.so.2 也是not found。如何添加它?
    • 我找到了这个帖子github.com/gliderlabs/docker-alpine/issues/219 ...我正在尝试不同的东西...如果您有任何想法,请告诉我
    • 无论您从哪里获得这些二进制文件,您都需要针对您当前的架构重新编译它们,或者静态编译它们以便它们不再依赖于外部文件。
    • @Charley :如果二进制格式不适合,即可执行文件不可加载或具有虚假的幻数,我认为您会收到不同的错误消息,而不仅仅是找不到可执行文件.
    【解决方案5】:

    我是这样解决的:

    rm /usr/glibc-compat/lib/ld-linux-x86-64.so.2
    ln -s /usr/glibc-compat/sbin/ldconfig /usr/glibc-compat/lib/ld-linux-x86-64.so.2
    

    编辑:解释: /usr/glibc-compat/sbin/ldconfig/usr/glibc-compat/lib/ld-linux-x86-64.so.2 都是 docker 容器中的普通文件,所以我尝试了其中一个。

    首先我删除了/usr/glibc-compat/sbin/ldconfig 并将其设为符号链接。但是我有一个错误,不记得是哪个。 接下来,我尝试删除 ld-linux-x86-64.so.2 并使其成为符号链接。那行得通。

    【讨论】:

    • 你能补充一些解释吗?
    • @jossefaz 我已经添加了我的解释
    【解决方案6】:

    现在我们可以用docker compose代替docker-compose

    对于 Alpine Linux,安装者为

    apk add docker-cli-compose
    

    如果你还是喜欢docker-compose,你可以在/usr/local/bin/docker-compose下保存一个文件,用a+x:

    #!/bin/sh
    docker compose $@
    

    那么你仍然可以运行使用docker-compose的旧脚本。

    【讨论】:

      猜你喜欢
      • 2019-01-16
      • 2015-01-25
      • 2021-11-23
      • 2017-09-25
      • 2016-04-19
      • 2018-05-23
      • 1970-01-01
      • 2021-09-16
      • 1970-01-01
      相关资源
      最近更新 更多