使用 AWS Lambda 的自定义运行环境,在其中运行已经达到生命周期终止的 Node.js v8 等运行环境
首先。
Node.js的版本更新速度相当快对吧。
AWS Lambda的运行时支持期也相应地加快了节奏。
我們知道你們希望我們進行正確的版本升級,但是如果我們不得不繼續使用 Node.js v8.10 作為 Lambda 函數的話,我們將使用自定義運行時來執行已經過時的運行時,以延長其使用壽命。
确认操作环境
-
- Arch Linux (2020.04.04)
-
- Docker 19.03.8-ce
- aws-cli 1.18.36
自定义运行时的使用方法。(Zì shí de
有关自定义运行时规范的详细信息,请参考官方文档。
为了使用自定义运行时,您需要在部署软件包或层中包含一个Node执行文件和一个用于启动处理程序函数的引导执行文件。由于本次假设您要使用现有的Lambda函数,所以不需要修改函数的部署软件包,只需在Lambda层中加载运行时即可。
为了创建Lambda Layer,我们将利用以下存储库:
https://github.com/lambci/node-custom-lambda
目前(2020/04/04),这个仓库中包含有关Node v10和v12的文件。
这次我们将fork这个仓库,并添加用于v8.10的文件,以创建一个Layer。
关于Bootstrap,它分别以C语言和JavaScript编写,代码文件分别位于v12.x/bootstrap.c和v12.x/bootstrap.js(v10.x也是如此)。
首先,编译了bootstrap.c并由AWS Lambda启动,接着它使用自定义运行时的Node执行bootstrap.js脚本。
bootstrap.js从AWS Lambda运行时接口接收函数调用事件,执行部署包中的脚本,并进行执行结果的POST操作。
由于上述存储库的bootstrap.js在Node v8.10中运行良好,
所以只需将Lambda Layer中包含的node执行文件更改为v8.10的文件即可完成所需的更改。
创建自定义运行时
从前面介绍的存储库中开始克隆。
需要使用Docker。
$ git clone https://github.com/lambci/node-custom-lambda.git
$ cd node-custom-lambda
基于v12.x目录,创建一个v8.10的目录。
$ cp -r v12.x v8.10
$ cd v8.10
我会删除v12.x的Layer文件。
$ rm layer.zip
在这个项目中,我们将在Docker上进行bootstrap.c的构建和Node的下载。
修改 config.sh 文件,并指定 Node 的版本。
< export NODE_VERSION=12.16.1
---
> export NODE_VERSION=8.10.0
我会进行构建。
$ ./build.sh
解压缩后,您将得到一个名为v8.10/layer.zip的文件夹。解压缩该文件夹后,其中包含以下文件。
layer
├── bin
│ └── node
├── bootstrap
└── bootstrap.js
我会先检查 Node 的版本。
$ ./layer/bin/node -v
v8.10.0
因为有准备好的测试,我将进行执行。
$ ./test.sh
完成了自定义运行时层。
自定义运行环境的部署
在仓库中已准备了publish.sh,但这个脚本会在所有地区部署。
这次我们只需要在ap-northeast-1部署,所以我们将使用AWS CLI手动创建Layer。
首先,将创建的图层文件(layer.zip)上传到任意的S3上。
aws s3api put-object --bucket ${BUCKET_NAME} --key nodejs/8.10.0/layer.zip --body layer.zip --output json
接下来,将创建Lambda层。
在这里我们将使用CloudFormation进行创建。
AWSTemplateFormatVersion: 2010-09-09
Parameters:
S3BucketName:
Description: A S3 bucket name contains layer.zip
Type: String
Resources:
Nodejs8Runtime:
Type: AWS::Lambda::LayerVersion
Properties:
Content:
S3Bucket: !Ref S3BucketName
S3Key: nodejs/8.10.0/layer.zip
Description: Layer for Node.js 8.10.0 Custom Runtime
LayerName: custom-runtime-nodejs-8
Outputs:
Nodejs8RuntimeLayerARN:
Description: A lambda layer ARN of Node.js 8.10.0 Custom Runtime
Value: !Ref Nodejs8Runtime
Export:
Name: !Sub ${AWS::StackName}-runtime-nodejs8
创建一个栈。
aws cloudformation create-stack --stack-name dev-lambdalayers-nodejs \
--template-body file://template.yml \
--parameter ParameterKey=S3BucketName,ParameterValue=${S3_BUCKET_NAME}
我将确认Layer是否已经创建。
$ aws lambda list-layer-versions --layer-name custom-runtime-nodejs-8
{
"LayerVersions": [
{
"LayerVersionArn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:custom-runtime-nodejs-8:1",
"Version": 1,
"Description": "Layer for Node.js 8.10.0 Custom Runtime",
"CreatedDate": "2020-04-04T16:59:31.629+0000"
}
]
}
创建和测试Lambda函数
我将测试上述创建的自定义运行时。
决定使用Serverless Framework来创建Lambda Function。
通过在provider.runtime中指定“provided”,可以使用自定义的运行时。
Lambda Layer会导入之前的Cloudformation Stack的Output,并指定ARN。
service: test-lambda-function
provider:
name: aws
runtime: provided
stage: dev
region: ap-northeast-1
functions:
hello:
handler: handler.hello
layers:
- 'Fn::ImportValue': dev-lambdalayers-nodejs-runtime-nodejs8
函数代码非常简单,只返回正在运行的Node.js版本。
module.exports.hello = async event => {
return process.version;
};
当你运行它时,如果返回了字符串 v8.10.0,则表示成功。
$ sls invoke -f hello
"v8.10.0"
请注意
- AWS公式のNode.jsランタイムにはaws-sdkが含まれていますが、この方法で作成したカスタムランタイムにはいずれのnpmパッケージも含まれていません。
最后
经过以上措施,现在可以在Lambda函数中使用Node v8延长寿命。
使用相同的方法,也可以运行Node v6和v4。
当然地进行版本升级是最好的选择,但是像node-gyp等本地模块经常会因升级而无法正常运行,所以它们可以用作临时解决措施。
这次使用的代码都已经上传到以下代码库中:https://github.com/uhey22e/node-custom-lambda。