为 Scikit-image 构建自定义 AWS Lambda 层
Posted
技术标签:
【中文标题】为 Scikit-image 构建自定义 AWS Lambda 层【英文标题】:Build custom AWS Lambda layer for Scikit-image 【发布时间】:2020-02-10 15:06:15 【问题描述】:大纲:我需要在一些 AWS lambda 函数中使用 scikit-image
,所以我希望构建一个包含 scikit-image
的自定义 AWS lambda 层。
我的问题通常适用于任何 python 模块,尤其是 scikit-learn,或者我认为的任何自定义层。
背景:经过大量谷歌搜索和阅读,似乎最好的方法是使用 docker 在本地运行 AWS lambda 运行时,然后在其中安装/编译 scikit-image(或任何其他您正在寻找的模块)。完成后,您可以将其作为自定义层上传/安装到 AWS。
这在概念上非常简单,但我正在努力寻找最佳实践方法来做到这一点。我已经完成了这项工作,但不确定我是否以最好/正确/最佳/安全的方式进行... 关于这方面的博客文章数以百万计略有不同,AWS 文档本身(恕我直言)过于详细,但跳过了一些基本问题。
我一直在努力关注两个不错的中型帖子,here 和 here ...向这些人致敬。
我的主要问题是:
-
在哪里可以找到最新的 AWS AMI docker 映像?
对于所谓的最新图像,有多个(甚至在亚马逊本身)多个位置/版本等。例如https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html,或https://cdn.amazonlinux.com/os-images/2.0.20190823.1/。
..这忽略了许多非亚马逊 github 托管的可能性,例如来自中等帖子 here 的lambci/lambda:build-python3.6
,或来自here 的onema/amazonlinux4lambda
。
为了安全性和最新性,我更喜欢使用亚马逊提供的 docker 映像。
-
链接到this AMI 的 AWS lambda 运行时 here 是 docker 映像吗?如果是(或不是)如何下载它以在本地运行?
您如何确保知道何时可能需要重建层,因为亚马逊更改了 AWS lambda 运行时,这会破坏您使用旧运行时的层?
最好构建(在 scikit-image 的情况下编译)docker AIM 容器内的 pip 安装模块,或者只是告诉 pip 下载预构建版本 并希望/相信它会获得最适合您正在运行的 AMI 的编译库?
基本上在这里我关心的是稳定性和性能。我想确保在这种情况下为 scikit-image 编译的库尽可能针对 AMI 容器进行优化。
-
下载并使用AWS's SAM 来完成所有这些工作会更好吗?(看起来有点矫枉过正而且很复杂,但它确实可以确保您使用的是“正确的”AMI docker 容器)
是否有任何(好的、可信赖的)预先构建的 lambda 层的回购(这可能使这一切成为一个有争议的问题)?我看了但找不到。
...感谢您的任何建议、想法和 cmets!
【问题讨论】:
【参考方案1】:有趣的几天搞清楚这一点。 ...希望下面的答案对任何努力弄清楚如何制作自定义层(适用于 python 以及其他语言)的人有所帮助。
在哪里可以找到最新的 AWS AMI docker 映像?
正如上面的 Greg 指出的那样,用于构建图层的“正确”docker 映像在哪里:lambci/lambda:build-python3.7
。这是他们使用的 docker 镜像的官方 SAM 存储库。
所有 AWS lambda 运行时环境(不仅仅是 python)的完整列表是 here
构建您自己的 AWS lambda 层的最佳方式是什么? ...构建自定义 python 模块层的最佳方法是什么?
迄今为止,我发现的最佳方法是将AWS's SAM结合与我在great博客here中使用的一些调整结合使用。
这些调整是必要的,因为(在我写这篇文章的时候)AWS SAM 允许您定义您的层,但实际上不会为您构建它们。 ...请参阅 SAM 组 github 中的 this request。
我不打算在这里详细解释这一点 - 请查看bryson3gps blog。他解释得很好,这一切都归功于他。*
好的,使用过程的快速背景:
目前,AWS SAM 不会为您构建您的层。
意思是,如果您为要安装在层中的一组模块定义了一个 requirements.txt,它实际上不会将它们安装/构建到准备上传到 AWS 的本地目录中(如果您用它来定义一个 lambda 函数)。
但是,如果您在 SAM 中定义一个层,它将打包(压缩所有内容并上传到 S3)并部署(使用 ARN 等在 AWS 云中定义它等所以它可以被使用)你的那个层。
让 SAM 也构建图层的方法
目前,从 bryson3Gps 博客here 中“欺骗”SAM 为您构建图层的方法是
-
在 SAM 中定义一个虚拟 AWS lambda 函数模板。
然后对于该功能,创建一个 pip
requirement.txt
,SAM 将在构建期间使用它来将您想要的模块加载到您的层中。您实际上不会将这个函数用于任何事情。
这需要制作一个定义基本功能的 SAM template.yaml
文件。查看 SAM 教程,然后查看 bryson3gps 的博客。这很容易。
在同一 template.yaml
文件中定义 AWS 层。再次不要太难 - 查看博客
在您的层定义的 SAM 规范中,将 ContentUri
(即它查找要压缩并上传到 AWS 的文件/目录的位置)设置为您在 ( 1).
所以,当您使用 sam build
时,它会为您构建函数(即为函数处理 requirements.txt
)并将生成的函数包放在一个目录中,以便稍后压缩并发送到 AWS。
但是(这是关键)您定义的层有 ContentUri
指向同一目录 sam build 用于为(虚拟)函数创建目录。
那么,当您告诉 SAM 为整个模板打包(发送到 S3)和部署(使用 AWS 配置)时,它将上传/创建您定义的层,但它也会使用为(虚拟)函数构建的图层的正确内容。
效果很好。
一些额外的提示
1
在 bryson3gps 的博客中,他指出此方法不会将层包放在 lambda AMI 目录中的正确位置,以便默认找到它们(对于 python 即 /opt/python)。相反,它们被放置在 /opt 中。
他的解决方法是在导入之前将 /opt 添加到 lambda 脚本中的 sys.path:
sys.path.append('/opt')
import <a module in your layer>
在 sam package
上传到 S3 之前(sam build
之后),您可以不这样做,而是进入适当的 .aws-sam/<your package subdir>
目录并将所有内容移动到该包目录中的新 /python 目录中。这导致层模块被正确放置在 /opt/python 中,而不仅仅是 /opt。
cd .aws-sam/<wherever you package is>/
mkdir .python
mv * .python
mv .python python
2
如果您正在使用已编译的代码制作 python 层(例如,我正在使用的 scikit-image)确保您使用 sam build -u
(带有 - u 标志)。
这将确保构建(pip'ing requirements.txt)将在与 AWS lambda 运行时匹配的 docker 容器内进行,因此将为运行时 DL 正确的库。
3
如果您包含任何依赖于 numpy 或 scipy 的模块,那么在 sam build -u 之后,但在打包/部署之前,确保 你进入适当的 .aws-sam/<your package>
目录并删除依赖项将安装的 numpy 和 scipy 模块
cd .aws-sam/<wherever you package is>/
rm -r numpy*
rm -f scipy*
您应该指定在您的 lambda 函数中使用 AWS 提供的 numpy/scipy 层。
我找不到告诉 SAM 使用 --no_dep 运行 pip 的方法,所以必须手动执行此操作
【讨论】:
如果我想用 sam local invoke 在本地测试我的 lambda 怎么办?这个程序有效吗?图层会上传到我的 docker 容器吗? 它确实有效 - 当您在本地运行时,它会从 S3 下载您的层以在本地机器上运行我相信。我认为使用图层的本地副本(如果存在)不够聪明。 您能提供一个示例文件结构吗?我还是很困惑。 为什么提示 #3(删除 numpy 和 scipy)是必须的?它会搞砸事情吗..? 它不会搞砸,但是 AWS 有自己的 scipy/numpy 层,您可以使用它来代替。它完全针对 EC3 性能进行了优化,所以我会使用它而不是你自己的【参考方案2】:从 v0.50.0 开始,sam cli 具有 direct support for building layers。你用元数据来装饰你的 AWS::Serverless::LayerVersion
资源,这些元数据是关于使用哪个运行时策略的。
MyLayer:
Type: AWS::Serverless::LayerVersion
Properties:
Description: Layer description
ContentUri: 'my_layer/'
CompatibleRuntimes:
- python3.8
Metadata:
BuildMethod: python3.8
【讨论】:
【参考方案3】:我不是这方面的专家,但我碰巧在同一天遇到了同样的问题。但是我可以回答问题#1 和#2。把它们弄乱: 2) AMI 不是 docker 镜像,它用于 EC2 实例。
1) 以下是我获得适当 docker 映像的方法:
我安装了 SAM cli 并执行了以下命令:
sam init --runtime python3.7(设置 hello world 示例) sam build -u(构建应用,-u 表示使用容器)
来自 sam build -u 的输出:
获取 lambci/lambda:build-python3.7 Docker 容器映像
所以你去。您可以直接从 dockerhub 获取映像,或者如果您安装了 SAM cli,则可以执行“sam build -u”。现在您有了图像,如果您不想要开销,就不必遵循完整的 SAM 工作流程。
【讨论】:
谢谢!我实际上发现了同样的事情,但是通过查看 SAM 的 github 问题列表的完全不同的路线。 ...对于大多数编写自己的层的人非常需要的东西,它并没有完全记录在案!无论如何,我花了一天时间更详细地解决这个问题 - 请参阅下面的答案。希望对您和其他人有所帮助以上是关于为 Scikit-image 构建自定义 AWS Lambda 层的主要内容,如果未能解决你的问题,请参考以下文章
我可以使用/覆盖 AWS OpsWork 的内置 unicorn::rails 配方安装自定义构建的 nginx 吗?
aws imagebuilder 理解并使用imagebuilder构建pcluster自定义ami
Packer 自定义映像构建失败并出现 ssh 身份验证错误