为 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/&lt;your package subdir&gt; 目录并将所有内容移动到该包目录中的新 /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/&lt;your package&gt; 目录并删除依赖项将安装的 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 自定义授权方 - 从 cookie 获取令牌

我可以使用/覆盖 AWS OpsWork 的内置 unicorn::rails 配方安装自定义构建的 nginx 吗?

aws imagebuilder 理解并使用imagebuilder构建pcluster自定义ami

Packer 自定义映像构建失败并出现 ssh 身份验证错误

Python scikit-image 拉取请求 Travis CI Python 2.7 构建失败

为 React 自定义 AWS Amplify 身份验证 UI