我正在尝试在this guide上进行扩展,方法是构建一个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'
这似乎与this question非常相似,但是我不在Lambda建筑物中使用PYTHONPATH
。
编辑:我向此软件包中的文件添加了一些调试代码,以试图了解其运行时环境。我还为通过CodePipeline部署到Lambda的another package添加了类似的调试功能(尽管该调试器不使用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()
此代码尝试确定Lambda的运行时环境的requests
中是否存在sys.path
模块-如果存在,则在何处。
对于此(启用SAM的)程序包,在任何地方都找不到requests
。在未启用SAM的程序包中,在requests
中发现了requirements.txt
(以及该程序包的所有其他/var/task
声明的依赖项)。
似乎CodeBuild没有将函数的依赖项与源代码捆绑在一起,或者CloudFormation没有部署这些依赖项。我怀疑这与以下事实有关:这是SAM定义的函数,而不是“原始的” Cloudformation函数。
This page说:“您还可以使用与AWS SAM集成的其他AWS服务来自动化您的部署”,但是我看不到如何让CodePipeline运行sam deploy
而不是{{ 1}}(尽管this page声称它们是同义词)。
EDIT2-我相信我已经找到了问题。对于上下文,回想一下,我有两个通过CodePipeline部署Lambda的程序包(或试图这样做)–这个问题中提到的一个程序包,将Lambda称为aws cloudformation deploy
,第二个程序包使用{{1 }}。第一个功能的代码定义为相对位置(即,对我的软件包中的目录的引用:AWS::Serverless::Function
),而第二个功能的Code是对S3位置的引用(在CodePipeline中获取) ,带有AWS::Lambda::Function
或CodeUri: main/
)
以下是第一个程序包的CodeBuild输出的示例:
Fn::GetArtifactAtt": ["built", "ObjectKey"]}
与第二个软件包的CodeBuild输出的相同输出进行比较:
...BucketName"]}
这表明第一个包的[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>
调用导致将文件(....
[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>
)上载到S3,该文件仅基于{{1 }},而第二个软件包的CodePipeline的Build阶段的“输出”是CodeBuild已在 in 中运行的目录的aws cloudformation package
-包括依赖项(由于调用到669099ba3d2258eeb7391ad772bf870d
)。
我可以通过简单地更改SAM模板函数的template.yaml
以引用S3位置来解决此问题-但这意味着我将无法测试对无需编辑模板即可在本地运行(例如,zip
),因为它会引用S3位置,因此不会受到本地更改的影响。
理想情况下,我想找到一种在打包并上传的S3文件中包含代码依赖项的方法。从本地测试看来,运行pip install
/ template.yaml
而不先运行sam local start-api
只会导致仅包含源代码(不存在依赖项)。但是,由于未在其中安装SAM,因此无法在CodeBuild中运行sam package
。
(这也表明我无意中部署了第二个程序包的测试相关性,因为需要将它们安装在CodeBuild中(以便运行测试))
答案 0 :(得分:1)
通过在main
目录而不是根目录中安装我的代码的依存关系,我找到了解决方案。但是,我相信一个更好的选择是使用layers来保存依赖项。
答案 1 :(得分:0)
CodeBuild构建环境(特别是在使用托管映像时)基于Ubuntu基本映像-在Lambda上运行时,这些依赖项可能不兼容。这是因为Lambda容器环境基于Amazon Linux-https://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html
您可以尝试通过以下方式解决此问题:将相关性打包在您的源包中,然后从“ requirements.txt”文件中跳过。
如果我没记错的话,可以通过-Using moviepy, scipy and numpy in amazon lambda
解决类似的问题答案 2 :(得分:0)
您的Lambda执行在实际的AWS Lambda执行环境中运行时会说"Unable to import module"
的原因是,您的Lambda部署软件包(通过aws cloudformation package
命令上传到S3)缺少了在您的 requirements.txt 。
aws cloudformation package
或sam package
这样的命令将通过压缩所有内容(无论它是否是源代码)与CloudFormation模板中的 AWS :: Serverless :: Function 资源一起使用,依赖项或其他任何东西)通过CodeUri
属性指定的目录中,然后它将生成的zip文件上传到S3存储桶,为您提供转换后的CloudFormation模板,其中部署包的S3存储桶路径替换了源路径CodeUri
属性中指定的本地计算机中的代码。
查看您的 buildspec.yml ,我认为问题出在 install 阶段在-t .
命令中指定的pip install -r hello_world/requirements.txt -t .
选项。这会将依赖项安装在当前目录(通常是项目的根目录)中,而不是 hello_world lambda函数的源代码所在的目录中。因此,在以后的aws cloudformation package
步骤中,依赖项不会与源代码一起压缩。
通常,当您创建lambda函数部署包(无论是启用SAM的Lambda还是原始版本的Lambda)时,您需要捆绑应用中使用的所有内容(源代码,依赖项,资源等)。通常,您可以通过以下方式做到这一点:-
如果它是启用SAM的CloudFormation模板,请使用sam build
命令。此命令将自动找到您的requirements.txt
并将指定的依赖项安装到.aws-sam
目录中,以准备上传到S3。
手动运行pip install -r requirements.txt
到正确的目录,将内容压缩为用于部署lambda函数的部署程序包。既可以在启用SAM的Lambda CloudFormation模板中使用,也可以使用。
答案 3 :(得分:0)
如果您的CodeUri
指向/main
,则在运行aws cloudformation package
时此文件夹的内容将被压缩并上传到S3,但没有依赖项。
运行sam package
的不同之处在于,它为您安装了requirements.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>
。