[やってみた] 2020年1月6日からAWS Lambda(Node.js 8.10)が作成できなくなっていて、去年のre:InventのWorkshopを復習したら躓いたので、node.js 10.x 用にLambda Layer作成して移行してみた #reinvent,
AWS事業本部の梶原@福岡オフィスです。去年のre:Inventで実施されていたWorkshopを今年に入って実施しようとすると見事に Node.js 8.10を使用するAWS Lambdaがランタイムサポートポリシーにより新規作成ができない状況となっていましたので移行しました
ランタイムサポートポリシー
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/runtime-support-policy.html
自分でAWS Lambdaを作成して修正できるものはいいんですが、公開されているS3などからソースを取得して、ワークショップで使用する環境をCloudFormation一発で作るワークショップなどではStackがエラーするケースがあります。(Bootstrapやカスタムリソースなど)
ということで、該当するCloudFormationのAWS Lambdaの部分のnodejs8.10
をnodejs10.x
に更新して
LambdaFunction: Type: 'AWS::Lambda::Function' Properties: Handler: index.handler MemorySize: 256 Runtime: nodejs8.10 # <== これを nodejs10.x にする
で動くかとおもったのですが(バージョン依存、モジュール依存してないやつは動くときもあります)、nodejs8.10で含まれていたモジュールがnodejs10.xで存在しない場合、実行時にrequire("uuid") 等でError: Cannot find module 'uuid'が発生します。
ということで、モジュール無いなら足せばいいじゃないということで、とりあえず、Lambda Layerを作成して対応したので共有します。
なお、自分が検証したのはuuid
のみですので、ほかのモジュール(特にライブラリが必要なImageMagic当たりが怪しい)で動かない等があるかもしれません。使用の際は自己責任で徹底的にテストすることを強くお勧めします。
AWS LambdaLayerの作成
AWS Lambda Layer用のzipを作成
ローカル環境でLayer用のzipファイルを作成します。
- node.jsのバージョンを10.xに
- zip用のフォルダを作成(node8_modules)
- Node.jsのLayerでつかうので、nodejsフォルダを作成
- node.js 8.10 からnode.js 10.xのランタイム環境から消えたモジュールをnpmで追加
- aws-sdkはランタイム環境に含まれるので削除,package-lock.jsonは不要なので削除
- ディレクトリ階層を保持した状態で、zipファイルを作成
追加するモジュールは選別してもいいかとおもいます(自分は無くなったモジュールをまとめてつくりました)
追加したモジュール |
---|
base64-js |
buffer |
dynamodb-doc |
events ieee754 |
imagemagick |
isarray |
jmespath |
lodash |
punycode |
querystring |
sax |
url |
uuid |
xml2js |
xmlbuilder |
ちなみに追加したモジュールは既存のnode.js8.10のソースを変更して /var/runtime/node_modules/
のパスからバージョン間の差異をとってます
$ nvm use 10 Now using node v10.18.0 (npm v6.13.4) $ mkdir node8_modules $ mkdir node8_modules/nodejs $ cd node8_modules/nodejs $ npm install base64-js buffer dynamodb-doc events ieee754 imagemagick isarray jmespath lodash punycode querystring sax url uuid xml2js xmlbuilder + dynamodb-doc@1.0.0 + imagemagick@0.1.3 + jmespath@0.15.0 + base64-js@1.3.1 + punycode@2.1.1 + events@3.0.0 + querystring@0.2.0 + lodash@4.17.15 + url@0.11.0 + uuid@3.3.3 + xml2js@0.4.23 + xmlbuilder@13.0.2 + buffer@5.4.3 + ieee754@1.1.13 + isarray@2.0.5 + sax@1.2.4 added 28 packages from 70 contributors and audited 39 packages in 5.804s found 0 vulnerabilities $ rm -rf ./node_modules/aws-sdk $ rm -rf ./package-lock.json $ cd ../ $ zip -r ../node8_modules.zip .
zipファイルを置くS3バケットを作成(スキップ可)
Lambda Layer用のzipファイルを置くS3バケットすでにある場合はスキップしてください。
AWS CLIでlambda-layers-$AWS_DEFAULT_REGION-$ACCOUNT_IDを作成してます。
注:Lambdaレイヤー&CloudFormationはリージョン依存なので、re:Inventでよく使われている米国東部 (バージニア北部)us-east-1
や米国西部 (オレゴン)us-west-2
で使用する場合は
AWS_DEFAULT_REGIONを変更してください
$ AWS_DEFAULT_REGION=ap-northeast-1 $ echo $AWS_DEFAULT_REGION $ ACCOUNT_ID=`aws sts get-caller-identity --query 'Account' --output text`; $ echo $ACCOUNT_ID $ LAMBDA_LAYER_S3BUCKET=lambda-layers-$AWS_DEFAULT_REGION-$ACCOUNT_ID $ echo $LAMBDA_LAYER_S3BUCKET
$ aws s3api create-bucket --bucket $LAMBDA_LAYER_S3BUCKET --region $AWS_DEFAULT_REGION --create-bucket-configuration LocationConstraint=$AWS_DEFAULT_REGION
AWS Lambda Layerを作成
- S3バケットにLambda Layer用のzipファイルをアップロード
- LambdaLayerを作成
$ aws s3 cp ../node8_modules.zip s3://$LAMBDA_LAYER_S3BUCKET/ $ aws lambda publish-layer-version --layer-name node8_modules_layer \ --content S3Bucket=$LAMBDA_LAYER_S3BUCKET,S3Key=node8_modules.zip --compatible-runtimes nodejs10.x nodejs12.x { "Content": {省略 }, "LayerArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:layer:node8_modules_layer", "LayerVersionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:layer:node8_modules_layer:1", "Description": "", "CreatedDate": "2020-01-09T10:54:43.318+0000", "Version": 1, "CompatibleRuntimes": [ "nodejs10.x", "nodejs12.x" ] }
AWS Lambda Layerの作成を確認
- AWS Lambda Layerの作成を確認し
- LayerVersionArn をメモします。
$ aws lambda list-layers --compatible-runtime nodejs10.x { "Layers": [ { "LayerName": "node8_modules_layer", "LayerArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:layer:node8_modules_layer", "LatestMatchingVersion": { "LayerVersionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:layer:node8_modules_layer:1", "Version": 1, "CreatedDate": "2020-01-09T10:54:43.318+0000", "CompatibleRuntimes": [ "nodejs10.x", "nodejs12.x" ] } } ] }
arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:layer:node8_modules_layer:1
LambaLayerをAWS Lambdaに追加する
CloudFormationの場合
- Runtime をnodejs10.xに更新
- 作成したLambaLayerを追加
LambdaFunction: Type: 'AWS::Lambda::Function' Properties: Handler: index.handler MemorySize: 256 Runtime: nodejs10.x # update form nodejs8.10 Layers: # Layerを追加 - arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:layer:node8_modules_layer:1 # 前の工程で取得したARNを記載
上記の修正をおこなったのち、スタックを作成するか、更新を実施してください
コンソールから
Lambdaの検証
更新したLambda関数の検証を実施します。
複数AWS Lambda関数がある場合もレイヤーの追加ですむので、検証も捗るかとおもいます。
まとめ
re:Invnetでおこなわれたワークショップのサンプルコード等が随時公開されていますが、今年に入りエラーすることが多かったのでしらべてみると AWS Lambdaのランタイムサポートのことをうっかり忘れていました。同じようにハマる人の助けになれば幸いです。 ちなみに、新規の作成ができなくなった状況で、既存のLambdaが実行できなくなるという状況ではありません(いまのところランタイムの廃止のアナウンスはありません) がnode.jsのバージョンを更新するときなどに依存モジュールの事を気にかけていただけるといいかとおもいます
参考情報
AWS>ドキュメント>AWS Lambda>開発者ガイド>ラインタイムポリシー
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/runtime-support-policy.html
AWS Lambda レイヤー
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-layers.html