Лямбда-функция AWS может импортировать модуль при локальном запуске, но не при развертывании - PullRequest
0 голосов
/ 28 декабря 2018

Я пытаюсь расширить это руководство , создавая CodePipeline для сбора изменений в GitHub, их сборки и развертывания изменений в моей Lambda.sam build --use-container; sam local start-api позволяет мне успешно вызывать функцию локально, но при развертывании функции в AWS код не может импортировать зависимость.

Мой код зависит от requests.Я должным образом включил это в мой requirements.txt файл:

requests==2.20.0

Мой buildspec.yml содержит инструкции по установке зависимостей

version: 0.1
phases:
  install:
    commands:
      - pip install -r hello_world/requirements.txt -t .
      - pip install -U pytest
  pre_build:
    commands:
      - python -m pytest tests/
  build:
    commands:
      - aws cloudformation package --template-file template.yaml --s3-bucket <my_bucket>
                                   --output-template-file outputTemplate.yml
artifacts:
  type: zip
  files:
    - '**/*'

Когда мой пакет собирается в CodeBuild, это подтверждается:

[Container] 2018/12/27 23:16:44 Waiting for agent ping 
[Container] 2018/12/27 23:16:46 Waiting for DOWNLOAD_SOURCE 
[Container] 2018/12/27 23:16:46 Phase is DOWNLOAD_SOURCE 
[Container] 2018/12/27 23:16:46 CODEBUILD_SRC_DIR=/codebuild/output/src775882062/src 
[Container] 2018/12/27 23:16:46 YAML location is /codebuild/output/src775882062/src/buildspec.yml 
[Container] 2018/12/27 23:16:46 Processing environment variables 
[Container] 2018/12/27 23:16:46 Moving to directory /codebuild/output/src775882062/src 
[Container] 2018/12/27 23:16:46 Registering with agent 
[Container] 2018/12/27 23:16:46 Phases found in YAML: 3 
[Container] 2018/12/27 23:16:46  PRE_BUILD: 1 commands 
[Container] 2018/12/27 23:16:46  BUILD: 1 commands 
[Container] 2018/12/27 23:16:46  INSTALL: 2 commands 
[Container] 2018/12/27 23:16:46 Phase complete: DOWNLOAD_SOURCE Success: true 
[Container] 2018/12/27 23:16:46 Phase context status code:  Message:  
[Container] 2018/12/27 23:16:46 Entering phase INSTALL 
[Container] 2018/12/27 23:16:46 Running command pip install -r hello_world/requirements.txt -t . 
Collecting requests==2.20.0 (from -r hello_world/requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/f1/ca/10332a30cb25b627192b4ea272c351bce3ca1091e541245cccbace6051d8/requests-2.20.0-py2.py3-none-any.whl (60kB)
...

Но когда я вызываю развернутую функцию, я получаю сообщение об ошибке:

Unable to import module 'app': No module named 'requests'

Это похоже на этот вопрос , но яя не использую PYTHONPATH в моем здании Lambda.


РЕДАКТИРОВАТЬ: я добавил код отладки к файлам в этом пакете, чтобы попытаться понять их среду выполнения.Я также добавил подобную отладку в другой пакет , который я развернул в Lambda через CodePipeline (хотя этот не использует SAM).Код отладки приведен ниже:

import os, sys
print('Inside ' + __file__)
for path in sys.path:
    print(path)
    if (os.path.exists(path)):
        print(os.listdir(path))
        for f in os.listdir(path):
          if f.startswith('requests'):
            print('Found requests!')
    print()

Этот код пытается определить, присутствует ли модуль requests в sys.path среды выполнения Lambda - и, если да, где.

Для этого (с поддержкой SAM) пакета requests нигде не найдено.В пакете без поддержки SAM requests (а также все другие объявленные requirements.txt зависимости пакета) были обнаружены в /var/task.

Похоже, что CodeBuild не являетсясвязывание зависимостей функции вместе с источником, или CloudFormation не развертывает эти зависимости.Я подозреваю, что это как-то связано с тем фактом, что это определенная SAM функция, а не «ванильная» функция Cloudformation.

На этой странице говорится, что «Вы также можете использоватьдругие сервисы AWS, которые интегрируются с AWS SAM для автоматизации ваших развертываний », но я не понимаю, как заставить CodePipeline запускать sam deploy вместо aws cloudformation deploy (хотя эта страница утверждает, что они являются синонимами).


EDIT2 - Я считаю, что я нашел проблему.Для контекста, вспомните, что у меня есть два пакета, которые развертывают Lambdas через CodePipeline (или пытаются) - один, упомянутый в этом вопросе, который ссылается на Lambda как AWS::Serverless::Function, и второй, который использует AWS::Lambda::Function.Код первой функции был определен как относительное местоположение (т. Е. Ссылка на каталог в моем пакете: CodeUri: main/), тогда как код второй функции * второй функции был ссылкой на местоположение S3 (извлечено в CodePipeline), с Fn::GetArtifactAtt": ["built", "ObjectKey"]} или ...BucketName"]})

Ниже приведен пример вывода CodeBuild первого пакета:

[Container] 2018/12/30 19:19:48 Running command aws cloudformation package --template-file template.yaml --s3-bucket pop-culture-serverless-bucket --output-template-file outputTemplate.yml 

Uploading to 669099ba3d2258eeb7391ad772bf870d  4222 / 4222.0  (100.00%) 
Successfully packaged artifacts and wrote output template to file outputTemplate.yml. 
Execute the following command to deploy the packaged template 
aws cloudformation deploy --template-file /codebuild/output/src110881899/src/outputTemplate.yml --stack-name <YOUR STACK NAME> 

Сравните с тем же выводом из вывода CodeBuild второго пакета:

....
[Container] 2018/12/30 16:42:27 Running command aws cloudformation package --template-file template.json --s3-bucket {BUCKET_NAME} --output-template-file outputTemplate.yml 

Successfully packaged artifacts and wrote output template to file outputTemplate.yml. 
Execute the following command to deploy the packaged template 
aws cloudformation deploy --template-file /codebuild/output/src282566886/src/outputTemplate.yml --stack-name <YOUR STACK NAME>

Это говорит о том, что вызов aws cloudformation package первого пакета приводит к загрузке файла (669099ba3d2258eeb7391ad772bf870d) на S3, который основан на только на содержимом template.yamlтогда как «выходные данные» этапа сборки CodePipeline второго пакета представляют собой zip каталога, в котором CodeBuild выполнял в - который включает в себя зависимости (из-за вызовов pip install).

Я мог бы обойти это, просто изменив template.yaml моей функции SAM-шаблона для ссылки на местоположение S3 - но это означало бы, что я не смогутестируйте обновления функции локально (например, sam local start-api) без редактирования шаблона, поскольку он будет ссылаться на местоположение S3 и поэтому не будет зависеть от локальных изменений.

В идеале я хочу найтиспособ включить зависимости кода в упакованный и загруженный файл S3.При локальном тестировании выясняется, что запуск sam package / aws cloudformation package без первого запуска sam build приводит к включению только исходного кода (без зависимостей).Однако я не могу запустить sam build в CodeBuild, поскольку SAM там не установлен.

(Это также говорит о том, что я непреднамеренно развертывал тестовые зависимости моего второго пакета - поскольку требовалось установить их в CodeBuild (для запуска тестов))

Ответы [ 4 ]

0 голосов
/ 03 июня 2019

Если ваш CodeUri указывает на /main, содержимое этой папки будет zip и загружено на S3 при запуске aws cloudformation package, но без зависимостей.

Разница при запуске sam package заключается в том, что он устанавливает для вас зависимости из needs.txt и выводит его в папку .aws-sam/build/<functionname>.

Итак, чтобы упаковать зависимости, вам нужно получить доступ к папке функций и установить зависимости локально, например,

  • pip install -r requirements.txt -t .
  • , затем выполните aws cloudformation package --s3-bucket <YOUR_BUCKET> --template-file <YOUR TEMPLATE YAML> --output-template-file <OUTPUT TEMPLATE NAME YAML>.
0 голосов
/ 30 декабря 2018

Я нашел «решение» для этого, установив зависимости моего кода в каталог main, а не в корневой каталог.Однако я считаю, что лучшим вариантом будет использование слоев для хранения зависимостей.

0 голосов
/ 21 мая 2019

Причина, по которой ваше лямбда-выполнение показывает "Unable to import module" при работе в реальной среде выполнения AWS Lambda, заключается в том, что в вашем пакете развертывания лямбда-выражений (который был загружен в S3 командой aws cloudformation package) отсутствуют необходимые зависимости, указанные в needs.txt .

Команда типа aws cloudformation package или sam package будет работать с ресурсом AWS :: Serverless :: Function в шаблоне CloudFormation путем архивирования всего содержимого (независимо отбудь то исходный код, зависимости или любой другой материал) в каталоге, указанном в свойстве CodeUri, он будет загружать полученный zip-файл в корзину S3, предоставляя преобразованный шаблон CloudFormation, где путь корзины S3 к вашему пакету развертывания заменяет путьк исходному коду на вашем локальном компьютере, указанному в свойстве CodeUri.

Глядя на ваш buildspec.yml , я думаю, что проблема связана с параметром -t ., который вы указали в pip install -r hello_world/requirements.txt -t .команда на этапе install .Это установит зависимости в текущем каталоге (обычно в корневом каталоге вашего проекта), а не в каталоге, в котором находится исходный код функции hello_world lambda.Таким образом, зависимости не будут заархивированы вместе с исходным кодом на последующем шаге aws cloudformation package.

Как правило, при создании пакета развертывания лямбда-функции (будь то SAM-совместимая или обычная лямбда-версия)Вам необходимо связать все (исходный код, зависимости, ресурсы и т. д.), которое используется в вашем приложении.Обычно это делается с помощью: -

  1. Используйте команду sam build, если это шаблон CloudFormation с поддержкой SAM.Эта команда автоматически найдет ваш requirements.txt и установит указанные зависимости в каталог .aws-sam при подготовке к загрузке на S3.

  2. Вручную запустите pip install -r requirements.txt в нужный каталог, куда попадает содержимоеупакован в пакет для развертывания лямбда-функции.Это работает как с SAM, так и с простым старым шаблоном Lambda CloudFormation.

0 голосов
/ 28 декабря 2018

Среды сборки CodeBuild (особенно при использовании управляемых образов) основаны на базовых образах Ubuntu - эти зависимости могут быть несовместимы при работе на Lambda.Это связано с тем, что контейнерные среды Lambda основаны на Amazon Linux - https://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html

. Вы можете попытаться исправить это, упаковав зависимость в ваш исходный комплект и пропустив ее из вашего файла «needs.txt».

Если я не ошибаюсь, аналогичная проблема решается по адресу - Использование moviepy, scipy и numpy в amazon lambda

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...