Docker Alpine executable binary not found even if in PATH - linux

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/

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:
Install one the glibc compatibility packages, libc6-compat or gcompat:
# 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.
Install proper glibc on Alpine, for providing all glibc methods and functionalities. There are glibc builds available for Alpine, which should be installed in the following procedure (example):
# 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...

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).

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.

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.

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).

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.

Related

apk not found error while changing to node-buster from Alpine base image

I have changed my image in docker from Alpine base image to node:14.16-buster, While running the code I am getting 'apk not found' error.
Sharing the codes snippet :
FROM node:14.16-buster
# ========= steps for Oracle instant client installation (start) ===============
RUN apk --no-cache add libaio libnsl libc6-compat curl && \
cd /tmp && \
curl -o instantclient-basiclite.zip https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip -SL && \
unzip instantclient-basiclite.zip && \
mv instantclient*/ /usr/lib/instantclient && \
rm instantclient-basiclite.zip
Can you please help here, what do I need to change?
The issue comes from the fact that you're changing your base image from Alpine based to Debian based.
Debian based Linux distributions use apt as their package manager (Alpine uses apk).
That is the reason why you get apk not found. Use apt install, but also keep in mind that the package names could differ and you might need to look that up. After all, apt is a different piece of software with it's own capabilities.
Buster images are based on the Debian version.
It doesn't support the APK default package manger is APT
For example you can do :
FROM node:15.14.0-buster-slim
RUN apt-get update && \
apt-get install -y \
curl \
jq \
git \
wget \
openssl \
bash \
tar \
net-tools && \
rm -rf /var/lib/apt/lists/*
RUN mkdir /app && \
chown node:node /app
APK is part of the Linux alpine version you have to change the base version if you want to use the APK.
The buster node images are Debian based. buster is the release name for Debian 10 (11 will be bullseye).
Debian uses APT for packaging. apt-get can be used from scripts
apt-get update && apt-get install libaio1 curl
libnsl2 is not available in Buster, but you might not need it

How to get rid of cryptography build error?

I am trying to build a dockerfile but the problem is when it trying to build specifically cryptography is not building.
MY Dockerfile
FROM python:3.7-alpine
ENV PYTHONUNBUFFERED 1
RUN apk update \
# psycopg2 dependencies
&& apk add --virtual build-deps gcc python3-dev musl-dev\
&& apk add postgresql-dev \
&& apk add build-base \
# Pillow dependencies
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
# CFFI dependencies
&& apk add libffi-dev py-cffi \
# Translations dependencies
&& apk add gettext \
# https://docs.djangoproject.com/en/dev/ref/django-admin/#dbshell
&& apk add postgresql-client \
# cairo
&& apk add cairo cairo-dev pango-dev gdk-pixbuf-dev poppler-utils
# fonts for weasyprint
RUN mkdir ~/.fonts
COPY ./fonts/* /root/.fonts/
# secret key (should be in docker-secrets, or we need to run minikube locally
RUN mkdir /etc/secrets
COPY secret.readme proxy_rsa_key* /etc/secrets/
# Requirements are installed here to ensure they will be cached.
COPY ./requirements /requirements
RUN pip install -r /requirements/local.txt
COPY ./compose/local/django/entrypoint /entrypoint
RUN sed -i 's/\r//' /entrypoint
RUN chmod +x /entrypoint
COPY ./compose/local/django/start /start
RUN sed -i 's/\r//' /start
RUN chmod +x /start
COPY ./compose/local/django/celery/worker/start /start-celeryworker
RUN sed -i 's/\r//' /start-celeryworker
RUN chmod +x /start-celeryworker
COPY ./compose/local/django/celery/beat/start /start-celerybeat
RUN sed -i 's/\r//' /start-celerybeat
RUN chmod +x /start-celerybeat
COPY ./compose/local/django/celery/flower/start /start-flower
RUN sed -i 's/\r//' /start-flower
RUN chmod +x /start-flower
WORKDIR /app
ENTRYPOINT ["/entrypoint"]
when I try to build my dockerfile it shows:
Building wheel for cryptography (PEP 517): finished with status 'error'
ERROR: Command errored out with exit status 1:
error: Can not find Rust compiler
----------------------------------------
ERROR: Failed building wheel for cryptography
I tried to solve but i couldn't. I am newbie in docker.Please help how to get rid of this problem.
cryptography < 3.5:
You can skip the rust installation and other related dependencies by adding the line below before apk add commands:
ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1
cryptography >= 3.5: Thanks #riptusk331
After this version rust will be required. Either install a specific version <3.5 or follow cryptography installation instructions. It is stated in the attached link that they are very aggressively explained in the docs.
Since the error is...
error: Can not find Rust compiler
...the solution is to install the rust compiler. You'll also need
cargo, the Rust package manager, and it looks like your Dockerfile
is missing openssl-dev.
The following builds successfully for me:
FROM python:3.7-alpine
ENV PYTHONUNBUFFERED 1
RUN apk add --update \
build-base \
cairo \
cairo-dev \
cargo \
freetype-dev \
gcc \
gdk-pixbuf-dev \
gettext \
jpeg-dev \
lcms2-dev \
libffi-dev \
musl-dev \
openjpeg-dev \
openssl-dev \
pango-dev \
poppler-utils \
postgresql-client \
postgresql-dev \
py-cffi \
python3-dev \
rust \
tcl-dev \
tiff-dev \
tk-dev \
zlib-dev
RUN pip install cryptography
Note that the above apk add ... command line is largely the same as
what you've got; I've just simplified the multiple apk add ...
statements into a single apk add execution.
pip install -U pip is what all I had to do
Some people might come here (Like I did) looking for a fix just for Python, not necessarily Alpine.
Several options are available, mentioned in the github issue. (only pick one of these)
You can install rust, as another answer mentioned
You can downgrade your cryptography version to 3.4.x
You can upgrade to pip version 19.1.1 or higher, which installs precompiled packages
I faced the same issue and in order to resolve it I tried out the following:
Answer provided by #larsks. RUN apk add cargo openssl-dev helped. But this resulted in a huge image size for me (>1GB). Best practice is to always target the bare-minimum with a small image size. This way, we don't expose ourselves to any external vulnerabilities.
Answer provided by Sabri Özgür, ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1. This worked great!
Based on the comment added by #riptusk331 for the earlier answer, simply ignoring the Rust build may only work for now, as Cryptography 3.5+ will start requiring Rust.
My solution just to be safe was;
...
ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1
...
RUN pip install cryptography==3.4.6
...
This way, I managed to keep the image size at a considerably lower value while getting the build to pass.
Editing pyvenv.cfg by adding in my .env:
CRYPTOGRAPHY_DONT_BUILD_RUST=1
then doing pip install cryptography, solved my issue.

How to install aws-cli on alpine?

I'm installing aws-cli on a docker swarm manager node running alpine (Linux 0317632a4ad9 4.9.59-moby #1 SMP Thu Mar 1 20:54:00 UTC 2018 x86_64 Linux). The aws-cli package for Alpine is currently listed in the community repo on the edge branch (1.18.55.r0). I modified /etc/apk/repositories to target this repo.
The install blew up looking for py3-urllib3, but I got around that and finally got a clean install with no errors, as below:
~ $ sudo apk add aws-cli#edge-comm
fetch http://dl-cdn.alpinelinux.org/alpine/edge/community/x86_64/APKINDEX.tar.gz
ERROR: unsatisfiable constraints:
py3-urllib3-1.25.9-r0:
masked in: #edge
satisfies: py3-botocore-1.16.12-r0[py3-urllib3<1.26]
~ $ sudo apk add py3-urllib3#edge aws-cli#edge-comm
(1/23) Installing groff (1.22.3-r1)
(2/23) Installing py3-six (1.10.0-r6)
(3/23) Installing py3-dateutil (2.6.0-r1)
(4/23) Installing libpng (1.6.37-r0)
(5/23) Installing freetype (2.7.1-r2)
(6/23) Installing libjpeg-turbo (1.5.3-r2)
(7/23) Installing lcms2 (2.8-r1)
(8/23) Installing openjpeg (2.3.0-r2)
(9/23) Installing tiff (4.0.10-r0)
(10/23) Installing libwebp (0.6.0-r0)
(11/23) Installing py3-pillow (4.1.0-r0)
(12/23) Installing py3-roman (2.0.0-r2)
(13/23) Installing py3-docutils (0.13.1-r0)
(14/23) Installing py3-jmespath#edge-comm (0.9.5-r0)
(15/23) Installing py3-urllib3#edge (1.25.9-r0)
(16/23) Installing py3-botocore#edge-comm (1.16.12-r0)
(17/23) Installing py3-s3transfer#edge-comm (0.3.3-r0)
(18/23) Installing py3-colorama#edge-comm (0.4.3-r0)
(19/23) Installing yaml (0.1.7-r0)
(20/23) Installing py3-yaml (3.12-r1)
(21/23) Installing py3-asn1 (0.2.3-r0)
(22/23) Installing py3-rsa (3.4.2-r1)
(23/23) Installing aws-cli#edge-comm (1.18.55-r0)
Executing busybox-1.26.2-r11.trigger
OK: 576 MiB in 81 packages
The binary is created at /usr/bin/aws, but crashes looking for an awscli module:
~ $ aws
Traceback (most recent call last):
File "/usr/bin/aws", line 19, in <module>
import awscli.clidriver
ModuleNotFoundError: No module named 'awscli'
Thanks!
For anybody who googles this,
I've been using the image node:12.16.1-alpine.
RUN apk add --no-cache \
python3 \
py3-pip \
&& pip3 install --upgrade pip \
&& pip3 install --no-cache-dir \
awscli \
&& rm -rf /var/cache/apk/*
RUN aws --version # Just to make sure its installed alright
# Should output aws-cli/1.18.69 etc.
Worked fine for me.
NOTE: apk --no-cache and pip3 --no-cache-dir are used to keep the Docker image lean by not retaining package cache.
We have aws-cli Alpine package now. So you can just run
apk add --no-cache aws-cli
to expand and update upon #Rose (4317383) 's answer ( and get awscli version 2 ):
the regular pip3 packet ( pip3 install awscliv2 && awscliv2 -i ) presents the following errors due to musl / non-glibc alpine implementations:
Error relocating /root/.awscliv2/binaries/aws: __strcat_chk: symbol not found
Error relocating /root/.awscliv2/binaries/aws: __snprintf_chk: symbol not found
Error relocating /root/.awscliv2/binaries/aws: __vfprintf_chk: symbol not found
Error relocating /root/.awscliv2/binaries/aws: __strdup: symbol not found
Error relocating /root/.awscliv2/binaries/aws: __stpcpy_chk: symbol not found
Error relocating /root/.awscliv2/binaries/aws: __vsnprintf_chk: symbol not found
Error relocating /root/.awscliv2/binaries/aws: __strncpy_chk: symbol not found
Error relocating /root/.awscliv2/binaries/aws: __strcpy_chk: symbol not found
Error relocating /root/.awscliv2/binaries/aws: __fprintf_chk: symbol not found
Error relocating /root/.awscliv2/binaries/aws: __strncat_chk: symbol not found
in doubt GLIBC is necessary , but if you are willing to invest ~100MB of space or you really need v2 , the following snippet would help
RUN apk --no-cache add \
binutils \
curl \
&& GLIBC_VER=$(curl -s https://api.github.com/repos/sgerrand/alpine-pkg-glibc/releases/latest | grep tag_name | cut -d : -f 2,3 | tr -d \",' ') \
&& curl -sL https://raw.githubusercontent.com/sgerrand/alpine-pkg-glibc/master/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub \
&& curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-${GLIBC_VER}.apk \
&& curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk \
&& apk add --no-cache \
glibc-${GLIBC_VER}.apk \
glibc-bin-${GLIBC_VER}.apk \
&& curl -sL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip \
&& unzip awscliv2.zip \
&& aws/install \
&& rm -rf \
awscliv2.zip \
aws \
/usr/local/aws-cli/v2/*/dist/aws_completer \
/usr/local/aws-cli/v2/*/dist/awscli/data/ac.index \
/usr/local/aws-cli/v2/*/dist/awscli/examples \
&& apk --no-cache del \
binutils \
curl \
&& rm glibc-${GLIBC_VER}.apk \
&& rm glibc-bin-${GLIBC_VER}.apk \
&& rm -rf /var/cache/apk/*
RUN awsv2 --version # Just to make sure its installed alright
if your scripts do not break with awscliv2 named as awscli, you might add :
RUN ln -s $(which awscliv2) /usr/bin/aws
RUN apk update \
&& apk --no-cache add curl \
&& apk --no-cache add unzip \
&& curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
&& unzip awscliv2.zip \
&& ./aws/install
I've been using the image node:14-alpine
apk add --update --no-cache curl ca-certificates \
&& curl -sL -o /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub \
&& curl -sL -o glibc-2.28-r0.apk https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk \
&& apk add glibc-2.28-r0.apk \
&& curl -sL -o glibc-bin-2.28-r0.apk https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-bin-2.28-r0.apk \
&& apk add glibc-bin-2.28-r0.apk \
&& curl -sL -o awscliv2.zip https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.0.30.zip \
&& unzip awscliv2.zip \
&& ./aws/install \
&& rm -Rf aws/ awscliv2.zip glibc-2.28-r0.apk glibc-bin-2.28-r0.apk \
&& aws --version
Yesterday, I spent quite some time to figure out how to build a slim aws-cli v2 image for ci pipelines (hence autocomplete and examples are removed) that does not suffer from the symbol not found problem.
After the glibc 2.35-r0 packages are installed, the symlink /lib64/ld-linux-x86-64.so.2 still points to the musl version of the library and not the glibc version. In glibc 2.34-r0 the symlink was replaced correctly, so I assume it is a bug in 2.35-r0.
This is my multi-staged Dockerfile to build an aws-cli 2.7.33 image:
FROM alpine:3.16.2 as base
ENV GLIBC_VER=2.35-r0
RUN set euo pipefail; \
apk --no-cache add curl; \
curl --silent --location https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub --output /etc/apk/keys/sgerrand.rsa.pub; \
curl --silent --location --remote-name https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-${GLIBC_VER}.apk; \
curl --silent --location --remote-name https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk; \
curl --silent --location --remote-name https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk; \
apk --no-cache add \
glibc-${GLIBC_VER}.apk \
glibc-bin-${GLIBC_VER}.apk \
glibc-i18n-${GLIBC_VER}.apk; \
# optional: add if needed, will add ~10mb to the final image
#/usr/glibc-compat/bin/localedef -i en_US -f UTF-8 en_US.UTF-8; \
# replace symlink to point to glibc version instead of musl version
ln -sf /usr/glibc-compat/lib/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2; \
apk --no-cache del curl glibc-i18n; \
rm -rf \
/var/cache/apk/* \
/etc/apk/keys/sgerrand.rsa.pub \
glibc*${GLIBC_VER}.apk
FROM base as builder
ARG AWS_CLI_VERSION=2.7.33
RUN set euo pipefail; \
apk --no-cache add curl; \
curl --silent --location --remote-name https://awscli.amazonaws.com/awscli-exe-linux-x86_64-${AWS_CLI_VERSION}.zip; \
unzip -q awscli-exe-linux-x86_64-${AWS_CLI_VERSION}.zip; \
aws/install; \
aws --version; \
rm -rf \
awscli-exe-linux-x86_64-${AWS_CLI_VERSION}.zip \
aws \
/usr/local/aws-cli/v2/*/bin/aws_completer \
/usr/local/aws-cli/v2/*/dist/aws_completer \
/usr/local/aws-cli/v2/*/dist/awscli/data/ac.index \
/usr/local/aws-cli/v2/*/dist/awscli/examples; \
apk --no-cache del \
binutils \
curl; \
rm -rf /var/cache/apk/*
FROM base
COPY --from=builder /usr/local/aws-cli/ /usr/local/aws-cli/
RUN ln -sf /usr/local/aws-cli/v2/current/bin/aws /usr/local/bin/aws
ENTRYPOINT ["aws"]
Solution
Here's what you guys are looking for.
https://github.com/robertd/alpine-aws-cdk/blob/master/Dockerfile.v2
It works with Alpine and AWS CLI v2.
Credits for "Robert Djurasaj"
use and add apk
'''
image:
name: rxmllc/alpine-aws-cli
before_script:
- apk --no-cache add curl
'''
please refer https://hub.docker.com/r/rxmllc/alpine-aws-cli
If you are using alpine latest image then this always works for me
- apt update && apt install curl zip jq -y
# install aws cli
- curl -sL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip && unzip -q awscliv2.zip && aws/install && rm -rf awscliv2.zip aws /usr/local/aws-cli/v2/*/dist/aws_completer /usr/local/aws-cli/v2/*/dist/awscli/data/ac.index /usr/local/aws-cli/v2/*/dist/awscli/examples
# verify aws cli installation
- aws --version
you can use in my opinion alpine does not support aws cli V2
RUN apk add --no-cache \
python3 \
py3-pip \
&& pip3 install --upgrade pip \
&& pip3 install --no-cache-dir \
awscli \
&& rm -rf /var/cache/apk/*
The method published on the official awscliv2 install page for general Linux works fine on Alpine.
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
unzip ./awscliv2.zip && \
rm -f ./awscliv2.zip && \
./aws/install -i /usr/local/aws -b /bin && \
rm -rf ./aws
Just clean up your zip and leftover install files.
https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
There is an official AWS-CLI image on docker hub published by Amazon, although it uses AmazonLinux2 and not Alpine. I will recommend you use it though.
Reference:
https://hub.docker.com/r/amazon/aws-cli
It's DockerFile:
https://github.com/aws/aws-cli/blob/v2/docker/Dockerfile
FROM amazonlinux:2 as installer
COPY awscli-exe-linux-x86_64.zip .
RUN yum update -y \
&& yum install -y unzip \
&& unzip awscli-exe-linux-x86_64.zip \
# The --bin-dir is specified so that we can copy the
# entire bin directory from the installer stage into
# into /usr/local/bin of the final stage without
# accidentally copying over any other executables that
# may be present in /usr/local/bin of the installer stage.
&& ./aws/install --bin-dir /aws-cli-bin/
FROM amazonlinux:2
RUN yum update -y \
&& yum install -y less groff \
&& yum clean all
COPY --from=installer /usr/local/aws-cli/ /usr/local/aws-cli/
COPY --from=installer /aws-cli-bin/ /usr/local/bin/
WORKDIR /aws
ENTRYPOINT ["/usr/local/bin/aws"]

Dockerfile build from source in one stage and then copy and install in second stage

I'm a novice to docker and to linux.
Im running on a Alpine base image and I want to keep my image as clean and lightweight as possible. I have to build and install some packages in my Dockerfile, specifically this.
I was wondering if there was any way for me to use docker multi-stage builds and build the MariaDB connector in one stage and copy the files to the next stage and then install it there.
I've tried to build it in a separate directory and copy it to a different machine to see if it's possible, but I've run into an issue where it cannot install without a number of files that are outside the built direcory.
If you want to build your lib in the first stage and use it in the later stage without all the libs and tools needed to compile it, you can use a multistage build as you say.
But, when you copy the builded lib, you need to install the shared library that was linked to it (here musl and unixodbc).
You can find them by running ldd:
/build/mariadb-connector-odbc-3.1.4 # ldd /usr/lib/libmaodbc.so
/lib/ld-musl-x86_64.so.1 (0x7fde6847b000)
libodbcinst.so.2 => /usr/lib/libodbcinst.so.2 (0x7fde683c5000)
libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7fde6847b000)
As musl should be already present, you only need to install back the unixodbc lib used for building the lib.
This is an example of Dockerfile for that:
FROM alpine AS build
# Add build dependencies
RUN apk add --no-cache alpine-sdk cmake unixodbc-dev mariadb-connector-c mariadb-connector-c-dev mariadb-static unixodbc
# Download the source code from github
ADD https://github.com/MariaDB/mariadb-connector-odbc/archive/3.1.4.tar.gz /build/mariadb-connector-odbc.tgz
# Build it
WORKDIR /build
RUN tar xzf mariadb-connector-odbc.tgz \
&& cd mariadb-connector-odbc-3.1.4 \
&& CFLAGS="$CFLAGS -I/usr/include/mysql" \
cmake \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INSTALL_LIBDIR=lib \
-DBUILD_SHARED_LIBS=True \
-DCMAKE_BUILD_TYPE=None \
. \
&& make install
# Final stage
FROM alpine
# Add the dependencies for the lib
RUN apk add --no-cache unixodbc
# Copy it from the build image
COPY --from=build /usr/lib/libmaodbc.so /usr/lib/libmaodbc.so
Answering just the question in the title: "Dockerfile build from source in one stage and then copy and install in second stage"
With cmake builds you can use an install prefix to create a psudo package and then merge that install directory into your final image's root. I don't know if this is good practice but it seems to work well.
A simple outline for illustration only:
build.sh
set -e # exit if error
TOP=$(pwd)
... # Fill in the blank
cmake -B./build
cd build
make -j
# Interesting part!
make DESTDIR=./install install
cp -r install "$TOP/install"
Dockerfile
FROM ubuntu:focal AS runtime-base
RUN apt-get update && apt-get install -y --no-install-recommends \
libfoo \
&& rm -rf /var/lib/apt/lists/*
#------------------------------------------------
FROM runtime-base AS build
RUN apt-get update && apt-get install -y --no-install-recommends \
libfoo-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /root
COPY build.sh
# Makes /root/install
RUN bash ./build.sh
#------------------------------------------------
FROM runtime-base
WORKDIR /root
COPY --from=build /root/install ./install
RUN cp -RT install/usr/ /usr/ && \
rm -r install && \
ldconfig
cp -RT:
The -T flag stops source/file1 from being copied to destination/source/file1 instead.

Is sklearn compatible with Linux-alpine?

I get an error when I try to build an alpine based docker image that includes the sklearn package.
I've tried a few variations of pip installation, different package combinations, and outdated versions of sklearn to see if they are compatible. I've also run the container in -it mode and tried to install the package manually from there. When I remove the sklearn line, the Dockerfile builds and the container runs just fine. Sklearn works in an Ubuntu:latest Dockerfile I've built, but I'm trying to reduce my footprint, so I was hoping to get it to work on alpine...
Here's my Dockerfile code:
FROM alpine:latest
RUN apk upgrade --no-cache \
&& apk update \
&& apk add --no-cache \
musl \
build-base \
python3 \
python3-dev \
postgresql-dev \
bash \
git \
&& pip3 install --no-cache-dir --upgrade pip \
&& pip3 install sklearn \
&& rm -rf /var/cache/* \
&& rm -rf /root/.cache/*
And here's the error I'm getting:
ERROR: Command "/usr/bin/python3.6 /usr/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py prepare_metadata_for_build_wheel /tmp/tmpqjsz0004" failed with error code 1 in /tmp/pip-install-xlvbli9u/scipy
Alpine Linux doesn't support PEP 513. I found that something like this works:
RUN apk add --no-cache gcc g++ gfortran lapack-dev libffi-dev libressl-dev musl-dev && \
mkdir scipy && cd scipy && \
wget https://github.com/scipy/scipy/releases/download/v1.3.2/scipy-1.3.2.tar.gz && \
tar -xvf scipy-1.3.2.tar.gz && \
cd scipy-1.3.2 && \
python3 -m pip --no-cache-dir install .

Resources