在 AWS Lambda 的子目录中打包 Python 依赖项
Posted
技术标签:
【中文标题】在 AWS Lambda 的子目录中打包 Python 依赖项【英文标题】:Packaging Python dependencies in subdirectory for AWS Lambda 【发布时间】:2018-09-25 04:00:20 【问题描述】:我遇到了一个关于为 AWS Lambda 构建 Python 3 应用程序的 article on serverlesscode.com,它建议使用 pip(或 pip3)在 /vendored 子目录中安装依赖项。我喜欢这个想法,因为它可以保持文件结构整洁,但我在实现它时遇到了一些问题。
我正在使用无服务器框架,并且我的模块以正常方式导入到我的代码中,例如from pynamodb.models import Model
我已经使用命令pip install -t vendored/ -r requirements.txt
在子目录中安装了我的各种依赖项(每个 requirements.txt),这似乎按预期工作 - 我可以看到子目录中安装的所有模块。
但是,当调用该函数时,我收到错误 Unable to import module 'handler': No module named 'pynamodb'
(其中 pynamodb 是已安装的模块之一)。
我可以通过将我的 pip 安装更改为项目根目录来解决此错误,即不在 /vendored 文件夹中 (pip install -t ./ -r requirements.txt
)。这将安装完全相同的文件。
必须有一个我丢失的指向子文件夹的配置,但谷歌搜索没有透露我是否需要以不同的方式导入我的模块,或者是否有一些其他的全局配置我需要更改。
总结一下:如何使用 Pip 将我的依赖项安装在项目的子文件夹中?
编辑:注意到 tkwargs 关于使用 serverless 插件进行打包的好建议,了解如何在没有 venv 的情况下完成此操作仍然很好,因为例子。主要目的不是为了简化打包(使用 pip 非常简单),而是通过避免根目录中的其他文件夹来保持我的文件结构更清晰。
【问题讨论】:
如果您尝试安装到vendored
以便更轻松地打包您的 Lambda 函数,我建议您使用 serverless-python-requirements 插件。在这种情况下,您可以使用 virtualenv 在本地进行开发,当您部署时,插件会负责打包您的功能
【参考方案1】:
我看到有些人在他们的 lambda 函数代码中使用 sys 模块将子目录(在本例中为 vendored)添加到他们的 python 路径中......我不喜欢将其作为解决方案,因为这意味着需要为每个 lambda 函数执行此操作,并且需要额外的样板代码。我最终使用的解决方案是修改 PYTHONPATH 运行时环境变量以包含我的子目录。例如,在我的 serverless.yml 中,我有:
provider:
environment:
PYTHONPATH: '/var/task/vendored:/var/runtime'
通过在此级别将其设置为环境变量,它将应用于您在 serverless.yml 中部署的每个 lambda 函数——如果出于某种原因您不想要,您也可以在每个 lambda 函数级别指定它它适用于所有人。
我不确定如何自我引用 PYTHONPATH 的现有值,以确保在添加自定义路径“/var/task/vendored”的过程中不会错误地覆盖它...很想知道如果其他人有。
【讨论】:
谢谢,效果很好。有趣的是,我在克隆上面引用的教程背后的代码时发现,实际上有一些代码包含/vendored
目录,但与这个示例相比,它相当冗长。
根据此处:docs.aws.amazon.com/lambda/latest/dg/…,PYTHONPATH
设置为 $LAMBDA_RUNTIME_DIR
开始,其中包含(除其他外)boto3 库。我假设你假设LAMBDA_RUNTIME_DIR=/var/runtime
。我在 AWS 中找不到任何提到环境变量相互引用的文档。如果是这样,那么在 serverless 中也不可能。
我认为当时我假设“LAMBDA_RUNTIME_DIR=/var/runtime”是正确的......据我所知,这仍然适用,但不是很面向未来。
请注意那些现在遇到类似问题的人和使用新的 Lambda 层 - 如果您是改变它。以上是关于在 AWS Lambda 的子目录中打包 Python 依赖项的主要内容,如果未能解决你的问题,请参考以下文章
如何在 AWS Lambda 中使用 Python 自定义包
试图在AWS Lambda上运行python脚本,但是如果加载virtualenv目录,Lambda会失败