简体   繁体   English

AWS Lambda Alpine Python Container 显示 IMAGE Launch 错误 exec 格式错误

[英]AWS Lambda Alpine Python Container shows IMAGE Launch error exec format error

I am writing a Lambda function to convert an excel file to PDF using unoconv with libreoffice, for this I am using alpine base image.我正在编写一个 Lambda 函数来使用 unoconv 和 libreoffice 将 excel 文件转换为 PDF,为此我使用的是 alpine 基础图像。 The Dockerfile is as follows. Dockerfile 如下。

# Define global args
ARG FUNCTION_DIR="/home/app/"
ARG RUNTIME_VERSION="3.9"
ARG DISTRO_VERSION="3.12"

# Stage 1 - bundle base image + runtime
# Grab a fresh copy of the image and install GCC
FROM python:${RUNTIME_VERSION}-alpine${DISTRO_VERSION} AS python-alpine
# Install GCC (Alpine uses musl but we compile and link dependencies with GCC)
RUN apk add --no-cache \
    libstdc++

# Stage 2 - build function and dependencies
FROM python-alpine AS build-image
# Install aws-lambda-cpp build dependencies
RUN apk add --no-cache \
    build-base \
    libtool \
    autoconf \
    automake \
    libexecinfo-dev \
    make \
    cmake \
    libcurl
# Include global args in this stage of the build
ARG FUNCTION_DIR
ARG RUNTIME_VERSION
# Create function directory
RUN mkdir -p ${FUNCTION_DIR}
# Copy handler function
COPY app.py ${FUNCTION_DIR}
COPY requirements.txt ${FUNCTION_DIR}
# Optional – Install the function's dependencies
RUN python${RUNTIME_VERSION} -m pip install -r /home/app/requirements.txt --target ${FUNCTION_DIR}
# Install Lambda Runtime Interface Client for Python
RUN python${RUNTIME_VERSION} -m pip install awslambdaric --target ${FUNCTION_DIR}

# Stage 3 - final runtime image
# Grab a fresh copy of the Python image
FROM python-alpine
# Include global arg in this stage of the build
ARG FUNCTION_DIR
# Set working directory to function root directory
WORKDIR ${FUNCTION_DIR}
# Copy in the built dependencies
COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}

#
ARG PUID=1000
ARG PGID=1000
#
RUN set -xe \
    && apk add --no-cache --purge -uU \
        curl icu-libs unzip zlib-dev musl \
        mesa-gl mesa-dri-swrast \
        libreoffice libreoffice-base libreoffice-lang-uk \
        ttf-freefont ttf-opensans ttf-ubuntu-font-family ttf-inconsolata \
    ttf-liberation ttf-dejavu \
        libstdc++ dbus-x11 \
    && echo "http://dl-cdn.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories \
    && echo "http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories \
    && echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \
    && apk add --no-cache -U \
    ttf-font-awesome ttf-mononoki ttf-hack \
    && rm -rf /var/cache/apk/* /tmp/*

RUN pip install unoconv

# (Optional) Add Lambda Runtime Interface Emulator and use a script in the ENTRYPOINT for simpler local runs
ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/bin/aws-lambda-rie
COPY entry.sh /
RUN chmod 755 /usr/bin/aws-lambda-rie /entry.sh
ENTRYPOINT [ "/entry.sh" ]
CMD [ "app.handler" ]

entry.sh file content is as follows. entry.sh 文件内容如下。

#!/bin/sh
if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then
    exec /usr/bin/aws-lambda-rie /usr/local/bin/python -m awslambdaric $1
else
    exec /usr/local/bin/python -m awslambdaric $1
fi

requirement.txt file content is as follows. requirements.txt 文件内容如下。

unotools
unoconv
boto3

the app.py file content is as follows. app.py 文件内容如下。

import sys
import boto3
import subprocess
import json

def handler(event, context):       
    bucketname = "somebucket"
    filename = "Sample/example.xlsx"
    outputfilename = filename.rsplit('.', 1)[0] + '.pdf'

    s3 = boto3.client('s3')

    try:
        s3.download_file(bucketname, filename, "file.xlsx")
    except Exception as e:
        return str(e)

    try:
        result = subprocess.run(['unoconv', '-f', 'pdf', "file.xlsx"], stdout=subprocess.PIPE)
    except Exception as e:
        return str(e)

    try:
        with open("file.pdf", "rb") as f:
            s3.upload_fileobj(f, bucketname, outputfilename)
    except Exception as e:
        return str(e)

    body = {
        "message": "Converted excel to pdf"        
    }
    response = {
        "statusCode": 200,
        "event": json.dumps(event),
        "body": json.dumps(body),
        "path": "app.py"
    }
    return response

I built this container and run the container locally and this works without problems.我构建了这个容器并在本地运行容器,这没有问题。 However, when I push the image to the ECR and update the function with new latest image, and run the test, it shows this error.但是,当我将图像推送到 ECR 并使用新的最新图像更新功能并运行测试时,它会显示此错误。

{
  "errorMessage": "RequestId: SOME_ID_HERE Error: fork/exec /usr/local/bin/python awslambdaric: no such file or directory",
  "errorType": "Runtime.InvalidEntrypoint"
}
IMAGE   Launch error: fork/exec /usr/local/bin/python awslambdaric: no such file or directory   Entrypoint: [/usr/local/bin/python awslambdaric]    Cmd: [app.handler]  WorkingDir: [/home/app/]

Looking at the error I assume this is something related to the architecture.查看错误,我认为这与架构有关。 Can someone help me understand what is causing the issue ?有人可以帮助我了解导致问题的原因吗?

The problem was the architecture, I was building my image on a Mac Mini M1.问题是架构,我在 Mac Mini M1 上构建我的图像。 When I built the image with providing --platform=linux/amd64 option, the error went away.当我通过提供 --platform=linux/amd64 选项构建映像时,错误消失了。 And of course, the only writable folder in Lambda function would be /tmp so, I would have to change that as well to work it correctly.当然,Lambda 函数中唯一可写的文件夹是 /tmp 因此,我也必须更改它才能正常工作。

我在 M1 Pro 上遇到了同样的问题,不得不使用docker buildx来解决这个问题。

docker buildx build --platform linux/amd64 -f ./Dockerfile -t myDockerTag .

Thanks a ton!万分感谢! These answers really pointed me in the right direction.这些答案确实为我指明了正确的方向。

Since the M1 uses ARM64, another option is to let it build arm64 by default and have the lambda function us that architecture由于 M1 使用 ARM64,另一种选择是让它默认构建 arm64 并让 lambda 函数我们该架构

docker build myDockerTag:latest .

then when using the Lambda CLI然后在使用 Lambda CLI 时

aws lambda create-function --region <region_name> --architecture arm64 --function-name <function_name> --package-type Image --code ImageUri=<ECR Image URI> --role <iam_role_url>

For anyone visiting this, the problem could also be due to the fact that the image has been built on a different CPU architecture than specified on AWS.对于访问此内容的任何人,问题还可能是由于该映像是在与 AWS 上指定的 CPU 架构不同的 CPU 架构上构建的。 For example, if you have built your image on an M1, you have to choose the option of arm64 in lambda image dialog.例如,如果您在 M1 上构建了映像,则必须在 lambda 映像对话框中选择arm64选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM