AWS LambdaのランタイムでNode.js 18を選ぶとAWS SDK for JavaScriptのバージョンが3になっています。 (LambdaのランタイムとしてNode.js 18が利用できるようになったのは2022年11月なのでこの記事は今更過ぎますね。)
Lambdaではaws-sdk
モジュールが内部に含まれているため、node_modules
に含めることなく、AWS SDKを利用することができます。
Node.js 16まではこのAWS SDKのバージョンが2となっていましたが、Node.js 18ではバージョン3となっています。
下に公式ブログからの情報を載せておきます。
Node.js 18.x runtime now available in AWS Lambda | AWS Compute Blog
Up until Node.js 16, Lambda’s Node.js runtimes have included theAWS SDK for JavaScript version 2. This has since been superseded by theAWS SDK for JavaScript version 3, which wasreleased in December 2020. With this release, Lambda has upgraded the version of the AWS SDK for JavaScript included with the runtime from v2 to v3.
以前からAWS SDK for JavaScriptはv2ではなく、v3を使いましょうね、と言われていたのでここで大きく変えてきたという感じでしょうか。 さらに、開発者ガイドからLambdaのNode.jsランタイムの環境を確認してみます。 Lambdaにデフォルトで含まれているSDKはNode.js 18からv3になっています。
Building Lambda functions with Node.js - AWS Lambda
v2を使い続けるには
さて、いきなりv3に変えるのは結構コードが違うこともあり、難しいのでv2を使い続けたいと思っていました。
方法があるようで、どうやらnode_modules
にAWS SDK v2を含めていればv2を利用できるようです(下がその根拠です。先述の公式ブログに記載されていました。)。
If your existing Lambda functions are using the included SDK v2, then you must update your function code to use the SDK v3 when upgrading to the Node.js 18 runtime. This is the recommended approach when upgrading existing functions to Node.js 18. Alternatively, you can use the Node.js 18 runtime without updating your existing code if you deploy the SDK v2 together with your function code.
訳すと、
既存のLambda関数が内部に含まれているSDK v2を利用している場合、Node.js 18ランタイムにアップグレードするとき、SDK v3を利用するようにLambda関数のコードを更新しなければなりません。これは既存の関数をNode.js 18をアップグレードするときに推奨されるアプローチです。代わりに、関数のコードとともにSDK v2をデプロイすることで既存のコードを更新することなく、Node.js 18ランタイムを利用することができます。
v2を使い続ける方法を試してみる
Lambda Node.js 18ランタイムで、デプロイするzipファイル(のnode_modules
以下)にaws-sdk v2を含めた場合、含めなかった場合にどうなるのかを実際に試してみました。
コードはGitHubにあります。
nodejs-module-labo/aws-sdk/aws-sdk-version · GitHub
動かすにはgit cloneし、npm install
してください。
AWSでLambda関数を作成しておきます。 ランタイムは当然Node.js 18とします。 このLambdaを実行するIAMロールにはIAMポリシーでLambdaのReadOnlyの権限を与えておきます。
aws-sdk v3を使ってみる
まずは、Lambda Node.js 18ランタイムの環境に含まれているaws-sdk v3を使ってみましょう。
コードを用意します。
先のGitHubにあるリポジトリでnpm run zip:v3
を実行します。
aws-sdk-version-v3.zip
というファイルが作成されます。
このzipファイルにはaws-sdkは含まれていません。
また、Lambdaで実行されるコードは以下となります(リポジトリ内のindex-v3.js
です)。
aws-sdk v3を使うコードです。
const { LambdaClient, ListFunctionsCommand } = require("@aws-sdk/client-lambda"); exports.handler = async (event) => { const client = new LambdaClient({ region: 'ap-northeast-1', }); const params = {}; const command = new ListFunctionsCommand(params); const data = await client.send(command); console.log(data); return; };
Lambdaにzipファイルをアップロードすることでデプロイします。 実行してみると、成功します。
Lambda Node.js 18ランタイムの環境にはaws-sdk v3が含まれているということがわかりました。
aws-sdk v2を使うがzipファイルに含めない
次にLambda Node.js 18ランタイムには含まれていないaws-sdk v2を使ってみます。
コードを用意します。先のGitHubにあるリポジトリでnpm run zip:v2-not
を実行します。
aws-sdk-version-v2-notincluded.zip
というファイルが作成されます。
このzipファイルにはaws-sdkは含まれていません。
Lambdaで実行されるコードは以下となります(リポジトリ内のindex-v2.js
です)。
aws-sdk v2を使うコードです。
const AWS = require('aws-sdk'); exports.handler = async (event) => { const lambda = new AWS.Lambda({ region: 'ap-northeast-1', }); const params = {}; lambda.listFunctions(params, function (err, data) { if (err) { console.log(err); return; } console.log(data); }); };
これをデプロイして実行すると、エラーが発生します。
aws-sdk
モジュールが見つからない、という内容です。
{ "errorType": "Runtime.ImportModuleError", "errorMessage": "Error: Cannot find module 'aws-sdk'\nRequire stack:\n- /var/task/index.js\n- /var/runtime/index.mjs", "trace": [ "Runtime.ImportModuleError: Error: Cannot find module 'aws-sdk'", "Require stack:", "- /var/task/index.js", "- /var/runtime/index.mjs", " at _loadUserApp (file:///var/runtime/index.mjs:996:17)", " at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1031:21)", " at async start (file:///var/runtime/index.mjs:1194:23)", " at async file:///var/runtime/index.mjs:1200:1" ] }
なるほど、公式情報のとおり、Lambda Node.js 18ランタイムの環境にはaws-sdk v2は含まれておらず、そのままでは動かなくなるのでaws-sdk v3に移行する必要があります。
aws-sdk v2をzipファイルに含める
さて次に解決策であるaws-sdk v2をzipファイルに含めた場合を確認してみます。
npm run zip:v2
を実行するとaws-sdk-version-v2.zip
というファイルが作成されます。
このzipファイルにはaws-sdk v2が含まれています。
Lambdaで実行されるコードは1つ前とおなじです(リポジトリ内のindex-v2.js
)。
デプロイして実行すると、実行に成功します。
こちらも情報通り、node_modules
にaws-sdk v2を含めることでソースコードを変更することなく、動作させられることが確認できました。
(おまけ)aws-sdk v2をzipファイルに含めた状態でaws-sdk v3を使う
npm run zip:v3-all
を実行すると、aws-sdk-version-v3a-all.zip
というファイルが作成されます。
ここではaws-sdk v2が存在する状態で、ソースコードとしてはv3を使ってみるというものになります。
競合とか変な動作をするかと思いましたが、問題なく動作しました。
まとめ
結果をまとめます。 Lambda Node.js 18ランタイムの環境で、
- aws-sdk v3を使うとき、aws-sdkv2とv3をzipファイルに含めない -> 動作する!
- aws-sdk v2を使うとき、aws-sdk v2をzipファイルに含めない -> エラー
- aws-sdk v2を使うとき、aws-sdk v2をzipファイルに含める -> 動作する!
- aws-sdk v3を使うとき、aws-sdk v2をzipファイルに含める -> 動作する!
なので、Node.js 18でもaws-sdk v2を使い続けるには、aws-sdk v2をデプロイするzipファイルに含めることが必要です。 これまでよりもデプロイするzipファイルのサイズが大きくなる可能性があることに注意しましょう。
また、2020年にaws-sdk v3はリリースされています。 これを機会に利用するaws-sdkのバージョン切り替えをおこなうべきなのでしょう。