Reputation: 3962
I have an alpine running container which contains some binaries in usr/local/bin
When I ls
the content of usr/local/bin
I got this output :
/usr/local/bin # ls
dwg2SVG dwg2dxf dwgadd dwgbmp dwgfilter dwggrep dwglayers dwgread dwgrewrite dwgwrite dxf2dwg dxfwrite
Which is what I expected.
However if I execute one of these binaries by calling it I got a not found
error from the shell :
/usr/local/bin # dwg2dxf
sh: dwgread: not found
/usr/local/bin # ./dwg2dxf
sh: ./dwgread: not found
I tested my $PATH
which seems to be correct :
/usr/local/bin # echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
How can I make those binaries callable or "foundable" ? Did I miss something in my Dockerfile build ?
I suppose that there is something with the ldconfig
command in alpine that went wrong but I'm not sure.
EDIT
As suggested in one answer here I executed the file
command and here is the output :
/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
Thoses binaries are from the LibreDWG Official repository as well as the first part of my Dockerfile. Here is the complete 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/
Upvotes: 89
Views: 124015
Reputation: 18661
On Alpine Linux, the not found
error is a typical symptom of dynamic link failure. It is indeed a rather confusing error by musl's ldd
linker.
Most of the world Linux software is linked against glibc, the GNU libc library (libc provides the standard C library and POSIX API). Most Linux distributions are based on glibc. OTOH, Alpine Linux is based on the musl libc library, which is a minimal implementation and strictly POSIX compliant. Executables built on glibc distributions depend on /lib/x86_64-linux-gnu/libc.so.6
, for example, which is not available on Alpine (unless, they are statically linked).
Except for this dependency, it's important to note that while musl attempts to maintain glibc compatibility to some extent, it is far from being fully compatible, and complex software that's built against glibc won't work with musl-libc, so simply symlinking /lib/ld-musl-x86_64.so.1
to the glibc path isn't likely going to work.
Generally, there are several ways for running glibc binaries on Alpine:
# apk add gcompat
apk add libc6-compat
Both packages provide a light weight glibc compatibility layer which may be suitable for running simple glibc applications.
libc6-compat
implements glibc compatibility APIs and provides symlinks to glibc shared libraries such as libm.so
, libpthread.so
and libcrypt.so
. The gcompat
package is based on Adelie Linux gcompat project and does the same but provides a single library libgcompat.so
. Both libraries install loader stubs. Depdending on the application, one of them may work while the other won't, so it's good to try both.
# 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
Use statically linked executables. Static executables don't carry dynamic dependencies and could run on any Linux.
Alternatively, the software may be built from source on Alpine.
For LibreDWG, let's first verify the issue:
/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
You can see that dwg2dxf
depends on several glibc symbols.
Now, let's follow option 2 for installing 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
Voila:
/usr/local/bin # ./dwg2dxf
Usage: dwg2dxf [-v[N]] [--as rNNNN] [-m|--minimal] [-b|--binary] DWGFILES...
Upvotes: 214
Reputation: 283
Now we can use docker compose
to replace docker-compose
For Alpine Linux, install by
apk add docker-cli-compose
If you still prefer docker-compose
, you can save a file under /usr/local/bin/docker-compose with a+x:
#!/bin/sh
docker compose $@
Then you still can run the old scripts which use docker-compose
.
Upvotes: -6
Reputation: 736
I solved it like this:
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
EDIT: explanation:
both /usr/glibc-compat/sbin/ldconfig
and /usr/glibc-compat/lib/ld-linux-x86-64.so.2
were normal files in the docker container, so I tried one of them.
First I removed /usr/glibc-compat/sbin/ldconfig
and made it a symlink. But I got an error, don't remember which.
Next I tried to remove ld-linux-x86-64.so.2
and make it a symlink. That worked.
Upvotes: 1
Reputation: 1117
Try apk add gcompat
(https://pkgs.alpinelinux.org/package/edge/community/x86/gcompat).
gcompat
provides both /lib64/ld-linux-x86-64.so.2
and /lib/ld-linux-x86-64.so.2
(https://pkgs.alpinelinux.org/contents?file=ld-linux-x86-64.so.2).
Upvotes: 40
Reputation: 3962
EDIT :
For a complete solution, please see the @valiano'response.
Here is just a workaround that I've found before reading the @valiano'response
WORKAROUND
I've found a workaround by switching to another base image (Ubuntu based) Here is the new working 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/
Basically I've just changed the
FROM osgeo/gdal:alpine-normal-latest
To
FROM osgeo/gdal:ubuntu-small-latest
I've updated the dependencies installation as well (switching from apk add
alpine PM to apt-get
)
This is not an ideal solution for me since using an alpine based image generate more lightweight container but it's working so I post it as a possible solution.
The @valiano'response is the optimal solution. Please refer to it if you care about lightweigth images.
Upvotes: 3
Reputation: 598
It may not be in a binary format you can use on the system in question. Check your architecture and the file format (for example using the file
command).
Edit:
Does /lib64/ld-linux-x86-64.so.2
exist? Can you run it?
Further edit: The general idea here is that a dynamically linked binary can be thought of as a script with an interpreter. See this LWN article for additional details to understand what may be going on here. If your binaries are for the wrong platform, you will need new binaries or you will need to run them on the proper platform.
Another thing you can check is whether the output of file
for this binary differs from the output of file
for binaries that are working correctly (e.g. /bin/ls
).
Upvotes: 0