aws-cli icon indicating copy to clipboard operation
aws-cli copied to clipboard

[v2] Distribute binaries for alpine / musl libc

Open jordanst3wart opened this issue 6 years ago • 61 comments
trafficstars

docker run -it --rm docker:latest sh
wget "https://d1vvhvl2y92vvt.cloudfront.net/awscli-exe-linux-x86_64.zip" -O "awscliv2.zip"
# curl not installed
unzip awscliv2.zip
./aws/install
# sudo not install

Errors with:

/ # ./aws/install
./aws/install: line 78: /aws/dist/aws2: not found
You can now run: /usr/local/bin/aws2 --version
/ # aws2
sh: aws2: not found

jordanst3wart avatar Nov 20 '19 01:11 jordanst3wart

I tried to debug the issue, and couldn't figure out why it fails. It seems to me the install script is just a bit flaky. I tried to add the v2 label as well.

jordanst3wart avatar Nov 20 '19 01:11 jordanst3wart

The binaries we publish won't work on docker images based on alpine because we're compiling them against glibc. The sh: aws2: not found is what happens when you try to execute this binary. If you try it on an image like ubuntu:latest the installer will work.

Additionally, I don't think we'd ever release an alpine compatible binary like we're doing for our general linux binary. I think we'd be more inclined to just release a docker image that comes with our binary built on alpine.

joguSD avatar Nov 20 '19 21:11 joguSD

Thanks for your answer. Is it possible to document that here https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html under "Prerequisites for Linux", or make the error more user friendly in the alpine based image case?

jordanst3wart avatar Nov 21 '19 00:11 jordanst3wart

We'll make sure to get this updated in the user guide. I also like the idea of making a more user friendly error message for this case.

kyleknap avatar Dec 03 '19 21:12 kyleknap

@joguSD bummer, alpine is the standard for docker images. Especially with build / ci systems wanting to automate & not wanting to continually download very large docker images.

Can use an official alpine docker image in a multi stage build to copy the binary into another docker image though.

chadgrant avatar Dec 26 '19 20:12 chadgrant

@chadgrant - can you give an example please of your multi-stage dockerfile?

BarakBD-Globality avatar Jan 07 '20 23:01 BarakBD-Globality

@BarakBD-Globality I do not have one but if the aws-alpine image ever gets created you can just do:

FROM aws_alpine_image:latest as aws
FROM alpine:latest
COPY --from=aws /usr/local/bin/binary /usr/local/bin/binary

chadgrant avatar Jan 07 '20 23:01 chadgrant

Too bad they don't support alpine. It is a standard image.

BarakBD-Globality avatar Jan 08 '20 08:01 BarakBD-Globality

Additionally, I don't think we'd ever release an alpine compatible binary like we're doing for our general linux binary. I think we'd be more inclined to just release a docker image that comes with our binary built on alpine.

@joguSD has there been any discussion or motion on this? It seems like a pretty big deal considering the prevalence of alpine. People like me use aws in their cicd and other automation, so if it's not available for alpine-based images, using version 2 is not even an option without significant work! Thanks.

jimbocoder avatar Feb 21 '20 20:02 jimbocoder

also can't install in busybox

maxkoryukov avatar Mar 20 '20 14:03 maxkoryukov

Interestingly if you use this as a base image the AWS cli will install and work properly.

FROM adoptopenjdk/openjdk11:alpine

I was able to do this using the following Dockerfile

FROM adoptopenjdk/openjdk11:alpine

RUN apk add --no-cache \
		ca-certificates \
		unzip \
		curl \
		groff \
		less  \
		bash  \
		openssh-client

WORKDIR /home
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
    && unzip awscliv2.zip \
    && ./aws/install \
    && rm awscliv2.zip \
    && rm -R aws

NavidMitchell avatar Apr 16 '20 19:04 NavidMitchell

The reason that the adoptopenjdk image works is because they include the missing glibc libraries. Alphine linux is based on 'musl glibc', a light-weight alternative to a fullblown glibc. The aws cli v2 binaries do not work with musl, they need a few more libraries to work.

Instead of using the Java image, you can also use the Dockerfile below as an example how to run AWS CLI v2 on Alpine Linux:

FROM alpine:3.11

ENV GLIBC_VER=2.31-r0

# install glibc compatibility for alpine
RUN apk --no-cache add \
        binutils \
        curl \
    && curl -sL https://alpine-pkgs.sgerrand.com/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/*

The above will download the glibc libraries, download and install AWS CLI v2, and remove some stuff we probably don't need, such as auto-complete. The resulting image is about 100MB in size

blagerweij avatar Apr 18 '20 13:04 blagerweij

So what's the shortest path to get a aws ecr get-login-password … | docker login … inside a docker container running? (which implies: docker:dind )?

I'd love to avoid to build my own docker:stable image with docker:dind support. At least I could thanks to https://github.com/aws/aws-cli/issues/4685#issuecomment-615872019 solution. Thanks for that!

bentolor avatar May 20 '20 17:05 bentolor

@bentolor Since docker:dind also uses alpine, I suspect all you have to do is change the first line of the above mentioned Dockerfile. Instead of FROM alpine:3.11 you should use FROM docker:dind. It does mean you're building your own image, though....

blagerweij avatar May 20 '20 20:05 blagerweij

thanks @blagerweij works really nicely

ChristophP avatar May 25 '20 12:05 ChristophP

Also thanks @blagerweij : I grasped the nettle and built a public, custom docker image by copy&pasting your solution: https://hub.docker.com/r/bentolor/docker-dind-awscli

bentolor avatar May 25 '20 14:05 bentolor

@bentolor I noticed in your repo that your Dockerfile uses FROM docker:stable instead of FROM docker:dind. I thought the whole point was to create an image for Docker in Docker with AWS support ?

blagerweij avatar May 25 '20 18:05 blagerweij

@blagerweij See the image below from the official Docker image for illustration.

The typical usage is:

  1. One (or your ci) starts a docker:dind instance and then
  2. Starts a separate docker:stable instance which is linked to the started docker:dind container
  3. You start executing docker commands inside the second container which redirects the comamnds via socket connection to docker daemon running inside the first docker:dind container.

Therefore: While it's true that the docker:dind instance eventually executes your Docker commands, your CLI frontend actually lives in a docker:stable instance. And that's the place where one i.e. needs to login into AWS ;-)

At least this is the usage pattern I'm aware of (i.e. on using Gitlab CI to build docker images). Maybe there are also direct docker:dind usage scenarios?

Usage of docker:stable vs. docker:didn

bentolor avatar May 25 '20 20:05 bentolor

One may use alpine image with glibc from https://hub.docker.com/r/frolvlad/alpine-glibc/ and install aws cli following steps from aws documentation. Worked for me.

vedant-khandelwal avatar May 27 '20 14:05 vedant-khandelwal

@blagerweij I used your script with the docker in docker image. aws cli works fine. I just got an error in build: /usr/glibc-compat/sbin/ldconfig: /usr/glibc-compat/lib/ld-linux-x86-64.so.2 is not a symbolic link

amiram avatar Jun 29 '20 10:06 amiram

@amiram Yes I also receive that message, that's a warning that you can simply ignore: It's expecting a symlink, but the file present is a regular file. See https://github.com/envoyproxy/envoy/issues/9078#issuecomment-576837432

blagerweij avatar Jun 29 '20 11:06 blagerweij

Could someone rename this issue to something like: "Distribute binaries for alpine / musl"?

@joguSD @jordanst3wart

mitchellrj avatar Jul 03 '20 11:07 mitchellrj

Yeah, i'm happy with "Distribute binaries for alpine / musl libc". Let me know if you have any issues

jordanst3wart avatar Jul 06 '20 02:07 jordanst3wart

I only need aws s3 cp for a passion project, so I just installed awscli V1 with pip:

FROM alpine:3.12
RUN pip install awscli        
RUN aws s3 ..

alanaalfeche avatar Aug 27 '20 00:08 alanaalfeche

The reason that the adoptopenjdk image works is because they include the missing glibc libraries. Alphine linux is based on 'musl glibc', a light-weight alternative to a fullblown glibc. The aws cli v2 binaries do not work with musl, they need a few more libraries to work.

Instead of using the Java image, you can also use the Dockerfile below as an example how to run AWS CLI v2 on Alpine Linux:

snip

The above will download the glibc libraries, download and install AWS CLI v2, and remove some stuff we probably don't need, such as auto-complete. The resulting image is about 100MB in size

this adjustment will fetch the latest version automatically if you don't want to hard code the glibc version:

FROM alpine

# install glibc compatibility for alpine
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://alpine-pkgs.sgerrand.com/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/*

jansepke avatar Sep 29 '20 19:09 jansepke

you can also use the Dockerfile below as an example how to run AWS CLI v2 on Alpine Linux:

The provided Dockerfile/script works but displays this error, which doesn't seem to prevent it from working:

aws/install: line 78: /aws/dist/aws: not found

Strangely, running apk add mandoc just before aws/install avoids displaying this error, and deleting that package after installing has no ill effect. Random other packages do not seem to have this protective effect.

Any thoughts?

P.S. apk add less is required for aws help to work correctly (it will complain about missing package groff otherwise).

erikeckhardt avatar Nov 04 '20 17:11 erikeckhardt

No need to install glibc to alpine.

FROM alpine:3.13
RUN apk add --no-cache \
    acl \
    fcgi \
    file \
    gettext \
    git \
    curl \
    unzip\
    python3-dev \
    py3-pip \
    gcc \
    linux-headers \
    musl-dev \
    libffi-dev \
    openssl-dev

RUN git clone --recursive  --depth 1 --branch v2 --single-branch  https://github.com/aws/aws-cli.git

WORKDIR aws-cli

RUN pip install --ignore-installed -r requirements.txt
RUN pip install -e .
RUN aws --version

Step 7/7 : RUN aws --version ---> Running in be6edcdd97d8 aws-cli/2.1.22 Python/3.8.7 Linux/5.8.0-41-generic source/x86_64.alpine.3 prompt/off

goshiz avatar Feb 02 '21 09:02 goshiz

No need to install glibc to alpine.

FROM alpine:3.13
RUN apk add --no-cache \
    acl \
    fcgi \
    file \
    gettext \
    git \
    curl \
    unzip\
    python3-dev \
    py3-pip \
    gcc \
    linux-headers \
    musl-dev \
    libffi-dev \
    openssl-dev

RUN git clone --recursive  --depth 1 --branch v2 --single-branch  https://github.com/aws/aws-cli.git

WORKDIR aws-cli

RUN pip install --ignore-installed -r requirements.txt
RUN pip install -e .
RUN aws --version

Step 7/7 : RUN aws --version ---> Running in be6edcdd97d8 aws-cli/2.1.22 Python/3.8.7 Linux/5.8.0-41-generic source/x86_64.alpine.3 prompt/off

Thanks for that !

anyone has time and able to convert that into a multi-stage building so we get only the necessary librairies and end up with an image without pip3, gcc ...etc ?

jgournet avatar Feb 22 '21 00:02 jgournet

Hard to do a multi-stage since aws install script move files on multiple locations. I think it's not a viable solution to copy each files in the long run. Best course of action IMHO is to remove all build packages after install.

Could be in the same RUN to reduce final size.

goshiz avatar Feb 22 '21 09:02 goshiz

Multi-stage would be has the advantage that its easier for merging into other images - maybe i have a php script, and to use from php:alpine but want to use the aws-cli for some reason

mcfedr avatar Feb 22 '21 10:02 mcfedr