在node.js(SAM)中尝试使用Lambda层
在2018年的re:Invent大会上,宣布了一个名为“Lambda Layers”的功能。通过这个功能,我终于能够解决“如何在多个Lambda函数之间同步和更新共享资源的问题”以及“当尝试使用小型函数时无法使用外部库的问题”。这应该会解决我的困扰。
参考资料
-
- 日本語ブログ記事
-
- Lambda ドキュメント
-
- Cloud Formation ドキュメント(英語)
- SAM ドキュメント
Lambda Layers是什么?
Lambda Layers是用于集中管理在多个函数中共享的代码和数据的工具。
[参考链接](https://aws.amazon.com/jp/blogs/news/new-for-aws-lambda-use-any-programming-language-and-share-common-components/)
首先是Layer。
我将在 Layer 中添加 moment.js,并尝试从 Lambda Function 中进行引用。
根据文件显示,Layer似乎以与Function相同的形式上传zip文件。
该zip文件的结构如下所示。
Node.js – nodejs/node_modules, nodejs/node8/node_modules (NODE_PATH)
Example AWS X-Ray SDK for Node.jsxray-sdk.zip
└ nodejs/node_modules/aws-xray-sdkhttps://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-layers.html
Node.js – nodejs/node_modules, nodejs/node8/node_modules (NODE_PATH)
Node.js示例中的AWS X-Ray SDKxray-sdk.zip
└ nodejs/node_modules/aws-xray-sdkhttps://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-layers.html
我会根据这个准备好本地环境。
$ mkdir -p layer/nodejs
$ cd layer/nodejs
$ npm init -y
$ npm install moment
$ cd ../..
$ zip -r ../layer.zip ./
adding: nodejs/ (stored 0%)
adding: nodejs/node_modules/ (stored 0%)
adding: nodejs/node_modules/moment/ (stored 0%)
adding: nodejs/node_modules/moment/CHANGELOG.md (deflated 71%)
adding: nodejs/node_modules/moment/ender.js (deflated 5%)
(以下略)
将刚刚解压的zip文件上传到合适的S3存储桶中。
$ cd ..
$ aws s3 cp ./layer.zip s3://<BUCKET>/
我会创建一个用于部署(包括Layer部署)的SAM模板。
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Resources:
SharedLayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: SharedLayer
Description: include moment
ContentUri: 's3://<BUCKET>/layer.zip'
CompatibleRuntimes:
- nodejs6.10
- nodejs8.10
LicenseInfo: 'Available under the MIT-0 license.'
RetentionPolicy: Retain
Outputs:
LayerVersionArn:
Value: !Ref SharedLayer
使用AWS CloudFormation的deploy命令进行部署。
aws cloudformation deploy \
--stack-name shared-layer \
--template-file layer-sam.yaml
我会在后面使用创建的Layer的Arn,所以请确认一下。
$ aws cloudformation describe-stacks --stack-name shared-layer --query "Stacks[].Outputs"
[
[
{
"OutputKey": "LayerVersionArn",
"OutputValue": "arn:aws:lambda:us-west-2:xxxxxxxxxxxx:layer:SharedLayer:1"
}
]
]
查看层的函数
我将创建一个使用Layer中的moment的函数。
const moment = require('moment');
exports.handler = async (event) => {
return {
moment: moment().format()
};
};
在functions目录下创建一个用于部署Func1的模板文件。
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Resources:
Func1:
Type: AWS::Serverless::Function
Properties:
CodeUri: Func1
Handler: index.handler
MemorySize: 128
Runtime: nodejs8.10
Timeout: 300
Layers:
- "arn:aws:lambda:us-west-2:xxxxxxxxxxxx:layer:SharedLayer:1"
在Layers属性中指定刚刚使用CloudFormation创建的Layer的Arn。
$ aws cloudformation package \
--template-file app-sam.yaml \
--s3-bucket <BUCKET> \
--output-template-file app-output_sam.yaml
由于app-output_sam.yaml已经准备好了,所以进行部署。
aws --region us-west-2 cloudformation deploy \
--stack-name layer-functions \
--template-file app-output_sam.yaml \
--capabilities CAPABILITY_IAM
让我们尝试执行该函数。
$ aws lambda invoke --function-name Func1 output.txt
$ cat output.txt
{"moment":"2018-12-02T14:49:29+00:00"}
通过这个,我们确认了Lambda函数的上传文件中能正确调用不包含的库。
在一些小规模的Lambda Function中,遇到了无法使用外部库的问题。
当我在ManagementConsole中使用Lambda Function进行试用时,以前是无法调用外部库的。
但是使用Layers似乎可以做到!我试了一下。

如果选择Layers,就可以进行“添加图层”的操作,然后点击即可。

选中之前创建的图层进行连接。
输入并执行以下代码。
const moment = require('moment');
exports.handler = async (event) => {
console.log(moment().format());
return {};
};
如果在日志中正确记录了,就是成功!

学科
在使用CodeBuild(或其他CI工具)测试函数时,如何确保以与实际运行时相同的Layer应用进行测试,特别是对于依赖于Layer的函数?