我正在尝试扩展 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 非常相似,但我没有使用
PYTHONPATH
在我的 Lambda 大楼里。编辑:我在这个包中的文件中添加了一些调试代码,以尝试了解它们的运行时环境。我还在 another package 中添加了类似的调试我通过 CodePipeline 部署到 Lambda(虽然这个不使用 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 函数。
This page说“您还可以使用与 AWS SAM 集成的其他 AWS 服务来自动化您的部署”,但我看不到如何让 CodePipeline 运行
sam deploy
而不是 aws cloudformation deploy
(尽管 this page 声称它们是同义词)。EDIT2 - 我相信我已经找到了问题。对于上下文,回想一下,我有两个包正在通过 CodePipeline(或尝试)部署 Lambda - 这个问题中提到的那个,它将 Lambda 称为
AWS::Serverless::Function
,第二个,它使用 AWS::Lambda::Function
.第一个函数的代码被定义为相对位置(即,对我的包中的目录的引用: CodeUri: main/
),而第二个函数的 Code是对 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 的 Build 阶段的“输出”是 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 中安装它们(以便运行测试))
最佳答案
你的 lambda 执行说 "Unable to import module"
的原因在实际的 AWS Lambda 执行环境中运行时,是因为您的 lambda 部署包(通过 aws cloudformation package
命令上传到 S3)缺少您的 requirements.txt 中指定的必需依赖项。
命令如 aws cloudformation package
或 sam package
将与 合作AWS::无服务器::函数 通过将所有内容(无论是源代码、依赖项还是任何其他内容)压缩到通过 CodeUri
指定的目录中,从而在 CloudFormation 模板中添加资源属性,然后它将生成的 zip 文件上传到 S3 存储桶,为您提供转换后的 CloudFormation 模板,其中您的部署包的 S3 存储桶路径替换了 CodeUri
中指定的本地计算机中源代码的路径属性(property)。
查看您的 buildspec.yml,我认为问题来自 -t .
您在 pip install -r hello_world/requirements.txt -t .
中指定的选项 中的命令安装阶段。这将在当前目录(通常是项目的根目录)中安装依赖项,而不是在 的源代码所在的目录中。 Hello World lambda函数驻留。因此,在后面的 aws cloudformation package
中,依赖项不会与源代码一起压缩。步。
通常,当您创建 lambda 函数部署包(无论是支持 SAM 还是普通 Lambda)时,您需要捆绑应用程序中使用的所有内容(源代码、依赖项、资源等)。您通常通过以下方式做到这一点:-
sam build
命令(如果它是启用 SAM 的 CloudFormation 模板)。这个命令会自动找到你的requirements.txt
并将指定的依赖项安装到 .aws-sam
准备上传到 S3 的目录。 pip install -r requirements.txt
到正确的目录,其中内容被压缩为用于部署 lambda 函数的部署包。这适用于支持 SAM 的或普通的 Lambda CloudFormation 模板。 关于amazon-web-services - AWS Lambda 函数可以在本地运行时导入模块,但在部署时不能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53952204/