SAM 构建 - 它也构建层吗?
SAM build - does it also build layers?
我对 lambda 和 SAM 都不熟悉 - 所以如果我搞砸了任何简单的事情,请不要大喊大叫 :D。
总结:我无法sam build
构建template.yaml
中指定的层,它只构建lambda函数。
背景:我正在尝试在 python3.7 中构建一个使用 skimage (scikit-image
) 模块的 lambda 函数。为此,我尝试使用 SAM 来构建和部署这一切。 ...这是有效的
我正在尝试将 scikit-image 模块部署为一个层(并且还使用 SAM 构建),而不是将其包含在 lambda 函数方向 ...这不起作用
首先,我只是扩展标准 SAM Hello World
应用程序。
我只需将 skimage 添加到 requirements.txt
,然后使用 sam build -u
,然后从构建的包目录中手动删除 numpy/scipy 依赖项(我有包含 AWS scipy/numpy 层)。
(我在标准的 hello world 应用程序中添加了 import numpy、scipy.ndimage 和 skimage.draw,并包含了对每个应用程序的一些测试函数调用)
requirements.txt:
requests
scikit-image
在那之后,一切正常(运行在本地 and/or 在 AWS 上)。
但是,我现在想将 skimage 模块从我的应用程序中移出并移到一个新的自定义层中(我想在一个层中使用 skimage 以重复使用一些功能)
为了设置它,我创建了一个依赖项目录并将 requirements.txt 移到那里(在 app 目录中留下空的 requirements.txt)。
然后我更新了 template.yaml 以指定新层:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.7
Layers:
- arn:aws:lambda:us-west-2:420165488524:layer:AWSLambda-Python37-SciPy1x:2
- !Ref SkimageLayer
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
SkimageLayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: Skimage
Description: Skimage module layer
ContentUri: dependencies/
CompatibleRuntimes:
- python3.7
RetentionPolicy: Retain
DependsOn:
- Skimage
目录结构:
▾ dependencies/
requirements.txt (responses and scikit-image)
▸ events/
▾ hello_world/
__init__.py
app.py
requirements.txt (now empty)
▸ tests/
README.md
template.yaml
但是,当我 运行 sam build -u
使用该模板文件时,没有为 ./dependencies
中指定的图层构建任何内容:template.yml 中的 SkimageLayer
文件。但是 HelloWorldFunction
仍然可以正确构建(现在当然没有任何包含的模块)
快速回答 - 否,当前 SAM 不 构建 您在SAM template.yaml
文件。
它将仅构建您定义的任何函数。
然而(奇怪的是)它 将 打包(上传到 S3)并部署(在 AWS 中设置,分配 ARN 以便它可以使用等)您定义的任何层。
有一个关于 SAM 的功能请求 github 问题以使用 SAM 实现层构建。
T实际上现在可以通过在 SAM 模板文件中创建一个虚拟函数以及一个层条目来让 SAM 也构建您的层,从而对其进行黑客攻击,并使层 ContentUri 入口指向为函数创建的 .aws-sam 构建目录。
这种方法实际上似乎非常适合现在扭曲 SAM 来为您构建图层。
我不确定最近是否发生了变化,但我可以毫无问题地执行此操作。我的模板文件和结构与 OP 非常相似,除了我将所有常用代码放入...
/dependencies/python/lib/python3.7/site-packages/
我没有在该目录中包含 requirements.txt 文件...只有 __init__.py
文件和我需要导入到我的函数中的各种 .py
文件。
SAM 然后找到代码并构建层。您甚至不需要像某些教程告诉您的那样压缩目录的内容。
最好的部分是 Layers:
可以放入模板文件的 Globals:
部分,以便该层可用于您的所有功能!
Globals:
Function:
Handler: main.lambda_handler
Timeout: 10
Runtime: python3.7
Layers:
- !Ref HelperFunctions
Resources:
HelperFunctions:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: MyHelperFunctions
Description: My Lambda Layer with Helper Functions for accessing RDS, Logging, and other utilities.
ContentUri: dependencies/
CompatibleRuntimes:
- python3.6
- python3.7
LicenseInfo: MIT
RetentionPolicy: Delete
我让它与以下脚本一起工作。使用 Ubuntu 18 和 CodeBuild
进行测试
它 pip 安装层的要求 .aws-sam/build/layername/python/
。然后你可以 运行 sam package
和 sam deploy
正常
build-layers.py
:
import yaml
import subprocess
import sys
import shutil
SAM_BUILD_PATH = ".aws-sam/build"
with open("template.yaml", "r") as f:
template = yaml.safe_load(f)
for key, resource in template["Resources"].items():
if resource["Type"] not in ["AWS::Serverless::LayerVersion", "AWS::Lambda::LayerVersion"]:
continue
properties = resource["Properties"]
content_uri = properties["ContentUri"]
layer_name = properties["LayerName"]
requirements_path = f"{content_uri}/requirements.txt"
subprocess.check_call([sys.executable, "-m", "pip", "install", "-r", requirements_path, "-t", f"{SAM_BUILD_PATH}/{layer_name}/python"])
shutil.copyfile("template.yaml", f"{SAM_BUILD_PATH}/template.yaml")
template.yaml
:
Transform: AWS::Serverless-2016-10-31
Resources:
pandas:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: pandas
ContentUri: pandas
CompatibleRuntimes:
- python3.6
- python3.7
- python3.8
sqlparse:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: sqlparse
ContentUri: sqlparse
CompatibleRuntimes:
- python3.6
- python3.7
- python3.8
所以先调用 python build-layers.py
,然后调用 sam package
,然后调用 sam deploy
我的目录如下所示:
lambda
layers
pandas
requirements.txt (content = pandas)
sqlparse
requirements.txt (content = sqlparse)
template.yaml
build-layers.py
buildspec.yml
:
--- # build spec for AWS CodeBuild
version: 0.2
phases:
install:
runtime-versions:
python: 3.8
commands:
- pip install aws-sam-cli
build:
commands:
- cd lambda/layers
- python build-layers.py
- sam package --s3-bucket foo --s3-prefix sam/lambda/layers | sam deploy --capabilities CAPABILITY_IAM -t /dev/stdin --stack-name LAYERS
自 SAM Cli version v0.50.0 以来,它正在构建图层作为 sam build
的一部分。
Design document 可能是了解其工作原理的一个很好的起点。
基本上,您必须使用 lambda 的目标运行时设置自定义 BuildMethod
:
MyLayer:
Type: AWS::Serverless::LayerVersion
Properties:
ContentUri: my_layer
CompatibleRuntimes:
- python3.8
Metadata:
BuildMethod: python3.8 (or nodejs8.10 etc..)
警告:对于Java这样的编译语言,它has a issue which it tries to build layers before functions. It's expected to have it fixed on the next release (PR opened already).
相对于这些较旧的答案,AWS 团队一定让事情变得更容易了。从当前文档中,您所做的就是在模板中将图层列为 属性(2020 年 11 月):
ServerlessFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: .
Handler: my_handler
Runtime: Python3.7
Layers:
- arn:aws:lambda:us-west-2:111111111111:layer:myLayer:1
- arn:aws:lambda:us-west-2:111111111111:layer:mySecondLayer:1
我对 lambda 和 SAM 都不熟悉 - 所以如果我搞砸了任何简单的事情,请不要大喊大叫 :D。
总结:我无法sam build
构建template.yaml
中指定的层,它只构建lambda函数。
背景:我正在尝试在 python3.7 中构建一个使用 skimage (scikit-image
) 模块的 lambda 函数。为此,我尝试使用 SAM 来构建和部署这一切。 ...这是有效的
我正在尝试将 scikit-image 模块部署为一个层(并且还使用 SAM 构建),而不是将其包含在 lambda 函数方向 ...这不起作用
首先,我只是扩展标准 SAM Hello World
应用程序。
我只需将 skimage 添加到 requirements.txt
,然后使用 sam build -u
,然后从构建的包目录中手动删除 numpy/scipy 依赖项(我有包含 AWS scipy/numpy 层)。
(我在标准的 hello world 应用程序中添加了 import numpy、scipy.ndimage 和 skimage.draw,并包含了对每个应用程序的一些测试函数调用)
requirements.txt:
requests
scikit-image
在那之后,一切正常(运行在本地 and/or 在 AWS 上)。
但是,我现在想将 skimage 模块从我的应用程序中移出并移到一个新的自定义层中(我想在一个层中使用 skimage 以重复使用一些功能)
为了设置它,我创建了一个依赖项目录并将 requirements.txt 移到那里(在 app 目录中留下空的 requirements.txt)。 然后我更新了 template.yaml 以指定新层:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.7
Layers:
- arn:aws:lambda:us-west-2:420165488524:layer:AWSLambda-Python37-SciPy1x:2
- !Ref SkimageLayer
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
SkimageLayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: Skimage
Description: Skimage module layer
ContentUri: dependencies/
CompatibleRuntimes:
- python3.7
RetentionPolicy: Retain
DependsOn:
- Skimage
目录结构:
▾ dependencies/
requirements.txt (responses and scikit-image)
▸ events/
▾ hello_world/
__init__.py
app.py
requirements.txt (now empty)
▸ tests/
README.md
template.yaml
但是,当我 运行 sam build -u
使用该模板文件时,没有为 ./dependencies
中指定的图层构建任何内容:template.yml 中的 SkimageLayer
文件。但是 HelloWorldFunction
仍然可以正确构建(现在当然没有任何包含的模块)
快速回答 - 否,当前 SAM 不 构建 您在SAM template.yaml
文件。
它将仅构建您定义的任何函数。
然而(奇怪的是)它 将 打包(上传到 S3)并部署(在 AWS 中设置,分配 ARN 以便它可以使用等)您定义的任何层。
有一个关于 SAM 的功能请求 github 问题以使用 SAM 实现层构建。
T实际上现在可以通过在 SAM 模板文件中创建一个虚拟函数以及一个层条目来让 SAM 也构建您的层,从而对其进行黑客攻击,并使层 ContentUri 入口指向为函数创建的 .aws-sam 构建目录。
这种方法实际上似乎非常适合现在扭曲 SAM 来为您构建图层。
我不确定最近是否发生了变化,但我可以毫无问题地执行此操作。我的模板文件和结构与 OP 非常相似,除了我将所有常用代码放入...
/dependencies/python/lib/python3.7/site-packages/
我没有在该目录中包含 requirements.txt 文件...只有 __init__.py
文件和我需要导入到我的函数中的各种 .py
文件。
SAM 然后找到代码并构建层。您甚至不需要像某些教程告诉您的那样压缩目录的内容。
最好的部分是 Layers:
可以放入模板文件的 Globals:
部分,以便该层可用于您的所有功能!
Globals:
Function:
Handler: main.lambda_handler
Timeout: 10
Runtime: python3.7
Layers:
- !Ref HelperFunctions
Resources:
HelperFunctions:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: MyHelperFunctions
Description: My Lambda Layer with Helper Functions for accessing RDS, Logging, and other utilities.
ContentUri: dependencies/
CompatibleRuntimes:
- python3.6
- python3.7
LicenseInfo: MIT
RetentionPolicy: Delete
我让它与以下脚本一起工作。使用 Ubuntu 18 和 CodeBuild
进行测试它 pip 安装层的要求 .aws-sam/build/layername/python/
。然后你可以 运行 sam package
和 sam deploy
正常
build-layers.py
:
import yaml
import subprocess
import sys
import shutil
SAM_BUILD_PATH = ".aws-sam/build"
with open("template.yaml", "r") as f:
template = yaml.safe_load(f)
for key, resource in template["Resources"].items():
if resource["Type"] not in ["AWS::Serverless::LayerVersion", "AWS::Lambda::LayerVersion"]:
continue
properties = resource["Properties"]
content_uri = properties["ContentUri"]
layer_name = properties["LayerName"]
requirements_path = f"{content_uri}/requirements.txt"
subprocess.check_call([sys.executable, "-m", "pip", "install", "-r", requirements_path, "-t", f"{SAM_BUILD_PATH}/{layer_name}/python"])
shutil.copyfile("template.yaml", f"{SAM_BUILD_PATH}/template.yaml")
template.yaml
:
Transform: AWS::Serverless-2016-10-31
Resources:
pandas:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: pandas
ContentUri: pandas
CompatibleRuntimes:
- python3.6
- python3.7
- python3.8
sqlparse:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: sqlparse
ContentUri: sqlparse
CompatibleRuntimes:
- python3.6
- python3.7
- python3.8
所以先调用 python build-layers.py
,然后调用 sam package
,然后调用 sam deploy
我的目录如下所示:
lambda
layers
pandas
requirements.txt (content = pandas)
sqlparse
requirements.txt (content = sqlparse)
template.yaml
build-layers.py
buildspec.yml
:
--- # build spec for AWS CodeBuild
version: 0.2
phases:
install:
runtime-versions:
python: 3.8
commands:
- pip install aws-sam-cli
build:
commands:
- cd lambda/layers
- python build-layers.py
- sam package --s3-bucket foo --s3-prefix sam/lambda/layers | sam deploy --capabilities CAPABILITY_IAM -t /dev/stdin --stack-name LAYERS
自 SAM Cli version v0.50.0 以来,它正在构建图层作为 sam build
的一部分。
Design document 可能是了解其工作原理的一个很好的起点。
基本上,您必须使用 lambda 的目标运行时设置自定义 BuildMethod
:
MyLayer:
Type: AWS::Serverless::LayerVersion
Properties:
ContentUri: my_layer
CompatibleRuntimes:
- python3.8
Metadata:
BuildMethod: python3.8 (or nodejs8.10 etc..)
警告:对于Java这样的编译语言,它has a issue which it tries to build layers before functions. It's expected to have it fixed on the next release (PR opened already).
相对于这些较旧的答案,AWS 团队一定让事情变得更容易了。从当前文档中,您所做的就是在模板中将图层列为 属性(2020 年 11 月):
ServerlessFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: .
Handler: my_handler
Runtime: Python3.7
Layers:
- arn:aws:lambda:us-west-2:111111111111:layer:myLayer:1
- arn:aws:lambda:us-west-2:111111111111:layer:mySecondLayer:1