Я пытаюсь развернуть приложение Python на aws lambda. Он имеет несколько больших зависимостей Python, самые большие из которых - scipy и numpy. В результате размер моего приложения значительно превышает разрешенные 250 МБ.
Пытаясь найти способ уменьшить размер, я наткнулся на подход, подробно описанный здесь:
https://github.com/szelenka/shrink-linalg
По сути, при установке с использованием pip во время компиляции scipy & numpy cython флаги могут быть переданы компилятору c, который оставит отладочную информацию в скомпилированных двоичных файлах c. В результате scipy и numpy уменьшаются примерно до 50% от исходного размера. Я смог запустить это локально (ubuntu 16.04) и без проблем создал двоичные файлы. Используемая команда была:
CFLAGS = "-g0 -I/usr/include:/usr/local/include -L/usr/lib:/usr/local/lib" pip install numpy scipy --compile --no-cache-dir --global-option=build_ext --global-option = "-j 4"
Проблема в том, что для работы с лямбда-выражением aws двоичные файлы должны быть скомпилированы в среде, аналогичной той, в которой выполняется лямбда-выражение. Изображение окружающей среды можно найти здесь:
https://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html
После загрузки образа в экземпляр ec2 я попытался запустить ту же установку pip после установки нескольких зависимостей.
sudo yum install python36 python3-devel blas-devel atlas atlas-devel lapack-devel atlas-sse3-devel gcc gcc-64 gcc-gfortran gcc64-gfortran libgfortran, gcc-c++ openblas-devel python36-virtualenv
Numpy компилируется нормально, но scipy - нет. Cython не вызывает никаких проблем, но компиляция fortran вызывает. Я получаю следующую ошибку:
error: Command "/usr/bin/gfortran -Wall -g -Wall -g -shared build/temp.linux-x86_64-3.6/build/src.linux-x86_64-3.6/scipy/integrate/_test_odeint_bandedmodule.o build/temp.linux-x86_64-3.6/build/src.linux-x86_64-3.6/build/src.linux-x86_64-3.6/scipy/integrate/fortranobject.o build/temp.linux-x86_64-3.6/scipy/integrate/tests/banded5x5.o build/temp.linux-x86_64-3.6/build/src.linux-x86_64-3.6/scipy/integrate/_test_odeint_banded-f2pywrappers.o -L/usr/lib64/atlas -L/usr/lib/gcc/x86_64-amazon-linux/6.4.1 -L/usr/lib/gcc/x86_64-amazon-linux/6.4.1 -L/usr/lib64 -Lbuild/temp.linux-x86_64-3.6 -llsoda -lmach -llapack -lptf77blas -lptcblas -latlas -lptf77blas -lptcblas -lpython3.6m -lgfortran -o build/lib.linux-x86_64-3.6/scipy/integrate/_test_odeint_banded.cpython-36m-x86_64-linux-gnu.so -Wl,--version-script=build/temp.linux-x86_64-3.6/link-version-scipy.integrate._test_odeint_banded.map" failed with exit status 1
Я попытался переустановить gfortran, а также всю коллекцию gcc, но безуспешно. К сожалению, у меня очень ограниченный опыт работы с компиляторами fortran. Если у кого-то есть идеи или скомпилированная версия двоичных файлов c, я был бы весьма признателен.
К сожалению нет. Отслеживание Пипа не очень помогает. Перед этим он просто показывает все, что успешно скомпилировано.
Возможно, вы сможете запустить pip в подробном режиме. Почти наверняка информации больше (даже если она от вас скрыта)
Или, если подробный режим недоступен, где-то должен быть какой-то файл журнала.
Я делаю аналогичные вещи в DOCKER, есть образ докера для amazon-linux, и с небольшим монтажом взад и вперед вы можете создать достойный процесс сборки





Итак, я решил это, хотя и довольно хакерским способом.
Флаги, которые я передавал в pip, были предназначены для уменьшения размера зависимостей c, а не зависимостей fortran. Так что действительно не было проблем с использованием предварительно скомпилированных зависимостей fortran, которые обычно загружаются через pip.
Итак, сначала я создал эталонную версию неизмененного пакета scipy в папке sp:
pip install scipy -t sp
Затем я создал программу go, которая действует как оболочка для компилятора gfortran (или технически вокруг ссылки на компилятор gfortran в / usr / bin)
package main
import "os"
import "strings"
import "io/ioutil"
import "log"
import "os/exec"
import "fmt"
func checkErr(err error) {
if err != nil {
log.Fatal(err)
}
}
func exists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil { return true, nil }
if os.IsNotExist(err) { return false, nil }
return true, err
}
func copyr(src string, dst string) {
// Read all content of src to data
data, err := ioutil.ReadFile(src)
checkErr(err)
// Write data to dst
err = ioutil.WriteFile(dst, data, 0644)
checkErr(err)
}
func main() {
search_folder := "/home/ec2-user/sp/scipy"
wrapped_compiler := "/usr/bin/inner_gfortran"
argsWithProg := os.Args
noProg := os.Args[1:]
primed := 0
check := "-o"
var (
cmdOut []byte
err error
)
for _, el := range argsWithProg {
if primed == 1{
primed = 0
s := strings.Split(el, "scipy")
if len(s) != 2{
continue
}
src := search_folder + s[1]
src_exi, _ := exists(src)
if src_exi == false {
continue
}
primed = 2
dir_parts := strings.Split(el, "/")
dir_parts = dir_parts[:len(dir_parts)-1]
dir := strings.Join(dir_parts,"/")
exi, _ := exists(dir)
if exi == false {
os.MkdirAll(dir, os.ModePerm)
}
os.Create(el)
copyr(src, el)
}
if el == check{
primed = 1
}
}
if primed == 0 {
if cmdOut, err = exec.Command(wrapped_compiler, noProg...).Output(); err != nil {
fmt.Fprintln(os.Stderr, "There was an error running fortran compiler: ", err)
os.Exit(1)
}
os.Stdout.Write(cmdOut)
}
}
Фактический компилятор перемещен в inner_gfortran
sudo mv /usr/bin/gfortran /usr/bin/inner_gfortran
И положите обертку на свое место
Оболочка передаст большинство инструкций компилятору, но если инструкция состоит в том, чтобы скомпилировать программу fortran в scipy, а скомпилированный двоичный файл уже существует в моей справочной версии scipy, оболочка просто копирует справочную версию в новую компилируемую версию. .
И это сделало это. Версии scipy и numpy уменьшенного размера теперь работают с aws lambda для python 3.6.
Я знаю, что вы давно не задавали этот вопрос, но, возможно, это поможет кому-то другому.
вы можете использовать лямбда-подобный контейнер докеров для компиляции ресурсов, а затем скопировать библиотеки обратно в среду разработки. использовать эти скомпилированные файлы в качестве лямбда-ресурсов
Эта статья мне очень помогла: https://medium.com/@mohd.lutfalla/how-to-compile-resources-for-aws-lambda-f46fadc03290
Использование пакета serverless-python-requirements на Бессерверный помогло мне упростить весь этот процесс, а также уменьшить размер пакета. Определенно рекомендую проверить это.
Это руководство, которому я следовал
Плагин бессерверных требований Python
Обязательно оставьте флаг strip для false, чтобы избежать удаления двоичных файлов, что приводит к проблеме «Адрес / смещение команды загрузки ELF неправильно выровнены»,
Это то, чем оказался мой последний serverless.yml, который дал мне результаты, которые я хотел упаковать sklearn + cv2 как слой:
custom:
pythonRequirements:
dockerizePip: true
useDownloadCache: true
useStaticCache: false
slim: true
strip: false
layer:
name: ${self:provider.stage}-cv2-sklearn
description: Python requirements lambda layer
compatibleRuntimes:
- python3.8
allowedAccounts:
- '*'
Я знаю, что это довольно старый вопрос, но теперь AWS Lambda позволяет запускать функции из образа Docker, хранящегося в ECR. Размер образа Docker может достигать 10 ГБ.
https://aws.amazon.com/fr/blogs/aws/new-for-aws-lambda-container-image-support/
Это последняя (и наименее информативная) строка сообщения об ошибке ... То, что она сообщает вам первой, вероятно, более полезно.