在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.js

xray-sdk.zip
└ nodejs/node_modules/aws-xray-sdk

https://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 SDK

xray-sdk.zip
└ nodejs/node_modules/aws-xray-sdk

https://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似乎可以做到!我试了一下。

image.png

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

image.png

选中之前创建的图层进行连接。

输入并执行以下代码。

const moment = require('moment');
exports.handler = async (event) => {
    console.log(moment().format());
    return {};
};

如果在日志中正确记录了,就是成功!

image.png

学科

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

bannerAds