#python #docker #aws-lambda #alpine #shapely
Вопрос:
У меня есть докер-файл на основе Alpine linux, который строит lambda.zip файл для AWS Lambda. Вот Докерфайл:
FROM alpine:3.12
# -- Install OS packages:
RUN apk add gcc
RUN apk add --update --no-cache
bash
build-base
cargo
curl
docker
# gcc
git
g
lftp
libc-dev
libffi-dev
libsodium-dev
libxslt-dev
libzmq
zeromq-dev
make
musl-dev
ncftp
nodejs
npm
openssh-client
openssl
openssl-dev
rsync
su-exec
tar
wget
zip
# geos
# geos-dev
# libc-dev
WORKDIR /tmp/
RUN echo "http://mirror.leaseweb.com/alpine/edge/community" >> /etc/apk/repositories
RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories
RUN apk add --virtual .build-deps
--repository http://dl-cdn.alpinelinux.org/alpine/edge/community
--repository http://dl-cdn.alpinelinux.org/alpine/edge/main
libc-dev geos-dev geos amp;amp;
runDeps="$(scanelf --needed --nobanner --recursive /usr/local
| awk '{ gsub(/,/, "nso:", $2); print "so:" $2 }'
| xargs -r apk info --installed
| sort -u)" amp;amp;
apk add --virtual .rundeps $runDeps
RUN geos-config --cflags
# -- Install python:
RUN apk add --update --no-cache python3-dev python3
amp;amp; python3 -m ensurepip --upgrade
amp;amp; pip3 install --upgrade pip pipenv setuptools docker-compose awscli shapely wheel
amp;amp; rm -r /usr/lib/python*/ensurepip
amp;amp; if [ ! -e /usr/bin/pip ]; then ln -s pip3 /usr/bin/pip ; fi
amp;amp; if [[ ! -e /usr/bin/python ]]; then ln
Вот скрипт, который работает с изображением docker Alpine и строит lambda.zip который содержит файлы python и все необходимые зависимости, такие как boto3, pip, six и т.д.
#!/bin/bash
set -x
set -e
pipenv install
rm -rf lambda.zip
VENV=$(pipenv --venv)
TEMPDIR=$(mktemp -d)
rsync -r --progress ./* ${TEMPDIR}
rsync -r --progress ${VENV}/lib/python3.8/site-packages/* ${TEMPDIR}
pushd ${TEMPDIR}
zip -r lambda.zip ./*
popd
cp ${TEMPDIR}/lambda.zip ./
cleanup() {
rm -rf ${TEMPDIR}
}
trap cleanup EXIT
Затем я копирую это lambda.zip на мой локальный компьютер, распакуйте его и включите pipenv на моем локальном компьютере, чтобы использовать только эти пакеты в lambda.zip и я пытаюсь протестировать стройную упаковку, например test.py:
from shapely.geometry import Polygon
print(Polygon([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]).minimum_clearance)
На AWS lambda и на моем локальном компьютере я получаю ту же ошибку с geos_c После:
Traceback (most recent call last):
File "test.py", line 1, in <module>
from shapely.geometry import Polygon
File "/home/stark/code/job/lamba_python_312_stack/shapely/geometry/__init__.py", line 4, in <module>
from .base import CAP_STYLE, JOIN_STYLE
File "/home/stark/code/job/lamba_python_312_stack/shapely/geometry/base.py", line 19, in <module>
from shapely.coords import CoordinateSequence
File "/home/stark/code/job/lamba_python_312_stack/shapely/coords.py", line 8, in <module>
from shapely.geos import lgeos
File "/home/stark/code/job/lamba_python_312_stack/shapely/geos.py", line 87, in <module>
_lgeos = load_dll('geos_c', fallbacks=alt_paths)
File "/home/stark/code/job/lamba_python_312_stack/shapely/geos.py", line 60, in load_dll
raise OSError(
OSError: Could not find lib geos_c or load any of its variants ['libgeos_c.so.1', 'libgeos_c.so'].
Если я распакую файл, у меня получится что-то вроде этого:
@user# ls
iohttp
aiohttp-3.7.4.post0.dist-info
attr
attrs-21.2.0.dist-info
boto3
boto3-1.18.38.dist-info
botocore
cron_runner.py
setuptools-58.0.4.virtualenv
shapely
Shapely-1.7.1.dist-info
...
xmltodict.py
yarl
yarl-1.6.3.dist-info
Я перепробовал множество различных решений в Интернете, так что вы можете увидеть беспорядок в моем файле Dockerfile, но они не сработали.
Ответ №1:
Вы устанавливаете некоторые статически скомпилированные зависимости в своей среде Docker, например libc-dev
geos-dev
, и geos
. Вы также должны включить эти статические зависимости в zip-файл развертывания Lambda. Кроме того, чтобы включить статически скомпилированные зависимости для использования в AWS Lambda, вы должны использовать ту же операционную систему, которую использует Lambda, то есть Amazon Linux, а не Alpine Linux.
К счастью, сейчас есть две альтернативы, которые значительно облегчают это:
Лямбда-слои-это лямбда-зависимости, которые могут быть упакованы в многоразовый метод, которым также можно поделиться с другими разработчиками. В этом случае кто-то уже создал красивый слой Лямбда (и кто-то еще здесь), который вы можете просто включить в свою функцию Лямбда, вместо того, чтобы пытаться упаковать его самостоятельно.
Если вы все еще хотите создать его самостоятельно, вы можете посмотреть исходный код этого проекта, чтобы узнать, как они создают слой.
Вместо создания развертывания zip вы можете создать образ Docker и развернуть его в Lambda. Если вы пойдете по этому пути, вам придется реализовать определенный интерфейс внутри вашего Лямбда-контейнера, и это проще всего сделать, начав с одного из официальных базовых образов AWS Lambda.