[アップデート] AWS Lambdaが Node.js 18をサポートしました

Lambdaがサポートするランタイムに Node.js 18 が加わりました
2022.11.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

早くNode.js 18使いたいな

こんにちは、のんピ(@non____97)です。

皆さんはそろそろNode.js 18使いたいなと思ったことはありますか? 私はあります。

AWS Lambdaがサポートしている昨日までのNode.jsの最新バージョンはv16です。

Node.js 16のサポート終了は2023/9/11です。

本来はNode.js 16はLTSで2024/4までサポート期間がありましたが、OpenSSL 1.1.1のサポート終了に合わせて7ヶ月繰り上げられています。

実際、Node.js 16のLambda関数で使用されているOpenSSLのバージョンを確認すると、OpenSSL 1.1.1でした。

exports.handler = async (event) => {
    console.log(process.versions);

    // TODO implement
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};
START RequestId: 6ff744dc-1cbc-4193-a34a-9eb44690aec5 Version: $LATEST
2022-11-19T00:13:57.674Z	6ff744dc-1cbc-4193-a34a-9eb44690aec5	INFO	{
  node: '16.16.0',
  v8: '9.4.146.24-node.21',
  uv: '1.43.0',
  zlib: '1.2.11',
  brotli: '1.0.9',
  ares: '1.18.1',
  modules: '93',
  nghttp2: '1.47.0',
  napi: '8',
  llhttp: '6.0.7',
  openssl: '1.1.1q+quic',
  cldr: '40.0',
  icu: '70.1',
  tz: '2021a3',
  unicode: '14.0',
  ngtcp2: '0.1.0-DEV',
  nghttp3: '0.1.0-DEV'
}
END RequestId: 6ff744dc-1cbc-4193-a34a-9eb44690aec5
REPORT RequestId: 6ff744dc-1cbc-4193-a34a-9eb44690aec5	Duration: 54.56 ms	Billed Duration: 55 ms	Memory Size: 128 MB	Max Memory Used: 57 MB	Init Duration: 148.75 ms

そんな折、AWS Lambdaが Node.js 18をサポートしました。

AWS公式ブログも投稿されていますね。

Node.js 18はNode.jsの最新のLTSリリースであり、2025年4月までセキュリティ&バグフィックスがサポートされます。

Node.js 17-18に追加された機能が使えるのは魅力的ですね。

加えて、私は特にランタイムにAWS SDK for JavaScript v3がバンドルされているのがハッピーなポイントだと思いました。

AWS SDKのバージョンは3.188.0のようです。

Name Identifier SDK Operating system Architectures Deprecation
Node.js 18 nodejs18.x 3.188.0 Amazon Linux 2 x86_64, arm64

抜粋 : Lambda runtimes - AWS Lambda

早速確認してみたので紹介します。

マネージメントコンソールから確認してみた

まず、マネージメントコンソールから確認します。

Node.js 18.xというランタイムが燦然と光輝いています。ランタイムをNode.js 18.x、アーキテクチャをarm64(なんとなく)を選択して、Lambda関数を作成します。

Node.js 18のLambda関数を作成

作成されたLambda関数のハンドラーを確認すると、index.mjsになっています。CJSではなくESMということがわかりますね。

作成されたLambda関数を確認

以下コードでNode.jsやv8エンジン、OpenSSLなどのバージョンを確認してみます。

exports.handler = async (event) => {
    console.log(process.versions);

    // TODO implement
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};

実行すると、Node.jsのバージョンは18.12.1で、V8エンジンのバージョンは10.2.154.15、OpenSSLのバージョンは3.0.7であることが分かりました。

START RequestId: c8f97dd3-ac1a-4fe2-863d-9496554b1775 Version: $LATEST
2022-11-19T00:29:35.602Z	c8f97dd3-ac1a-4fe2-863d-9496554b1775	INFO	{
  node: '18.12.1',
  v8: '10.2.154.15-node.12',
  uv: '1.43.0',
  zlib: '1.2.11',
  brotli: '1.0.9',
  ares: '1.18.1',
  modules: '108',
  nghttp2: '1.47.0',
  napi: '8',
  llhttp: '6.0.10',
  openssl: '3.0.7',
  cldr: '41.0',
  icu: '71.1',
  tz: '2022b',
  unicode: '14.0'
}
END RequestId: c8f97dd3-ac1a-4fe2-863d-9496554b1775
REPORT RequestId: c8f97dd3-ac1a-4fe2-863d-9496554b1775	Duration: 52.42 ms	Billed Duration: 53 ms	Memory Size: 128 MB	Max Memory Used: 63 MB	Init Duration: 211.15 ms

OpenSSLのバージョンは世間を賑わせたCVE-2022-3786とCVE-2022-3602の脆弱性を解消した3.0.7ですね。安心しました。

AWS CDKでデプロイしてみた

Node.js 18のLambda関数のデプロイはマネージメントコンソールからだけではなく、AWS CDKのv2.51.0からもできるようになっていました。

早速AWS CDKでデプロイしてみましょう。

実行するコードは以下のようにNode.jsのバージョン確認とsetTimeoutするだけだけのシンプルなものです。

./src/lambda/handlers/node-js-18-handler.ts

import { setTimeout } from "timers/promises";

console.log(`Node.js version : ${process.version}`);

console.log(`Start setTimeout outside of handler : ${new Date()}`);
await setTimeout(1000);
console.log(`End setTimeout outside of handler : ${new Date()}`);

export const handler = async (): Promise<void | Error> => {
  console.log(`Start setTimeout inside of handler : ${new Date()}`);
  await setTimeout(2000);
  console.log(`End setTimeout inside of handler : ${new Date()}`);

  return;
};

AWS CDK周りのコードは以下リポジトリに格納してあります。

npx cdk deployしてデプロイされたLambda関数を実行した結果は以下の通りです。

2022-11-19T07:01:24.823Z	undefined	INFO	Node.js version : v18.12.1
2022-11-19T07:01:24.825Z	undefined	INFO	Start setTimeout outside of handler : Sat Nov 19 2022 07:01:24 GMT+0000 (Coordinated Universal Time)
2022-11-19T07:01:25.827Z	undefined	INFO	End setTimeout outside of handler : Sat Nov 19 2022 07:01:25 GMT+0000 (Coordinated Universal Time)
START RequestId: 6cd5880c-2608-4efd-974e-6b38e34ba405 Version: $LATEST
2022-11-19T07:01:25.833Z	6cd5880c-2608-4efd-974e-6b38e34ba405	INFO	Start setTimeout inside of handler : Sat Nov 19 2022 07:01:25 GMT+0000 (Coordinated Universal Time)
2022-11-19T07:01:27.835Z	6cd5880c-2608-4efd-974e-6b38e34ba405	INFO	End setTimeout inside of handler : Sat Nov 19 2022 07:01:27 GMT+0000 (Coordinated Universal Time)
END RequestId: 6cd5880c-2608-4efd-974e-6b38e34ba405
REPORT RequestId: 6cd5880c-2608-4efd-974e-6b38e34ba405	Duration: 2017.90 ms	Billed Duration: 2018 ms	Memory Size: 128 MB	Max Memory Used: 65 MB	Init Duration: 1216.47 ms	
XRAY TraceId: 1-63787f44-7409c5120c006a323984c329	SegmentId: 26b5d68063cf25c6	Sampled: true

Node.jsのバージョンがv18.12.1とtop-level awaitが効いているのが分かりました。

AWS SDK for JavaScript v3を実行してみる

今までランタイムにバンドルされているAWS SDK for JavaScriptのバージョンはv2でしたが、Node.js 18からはv3に変わりました。

こちらも試してみます。

Lambda関数で実行する処理は指定したEC2インスタンスIDの情報を取得するといったものです。

./src/lambda/handlers/aws-sdk-js-v3-handler.ts

import { EC2Client, DescribeInstancesCommand } from "@aws-sdk/client-ec2";
import { Context } from "aws-lambda";

interface HandlerParameters {
  instanceIds: string[];
}

const ec2Client = new EC2Client({});

export const handler = async (
  event: HandlerParameters,
  context: Context
): Promise<void | Error> => {
  console.log(`event : ${JSON.stringify(event, null, 2)}`);

  await ec2Client
    .send(new DescribeInstancesCommand({ InstanceIds: event.instanceIds }))
    .then((instances) => {
      console.log(JSON.stringify(instances, null, 2));
    })
    .catch((error) => {
      console.error("Describe the EC2 Instance error!! \n\n", error);
    });

  return;
};

ランタイムにバンドルされていることを確認したいので、AWS CDKでデプロイする際にexternalModulesでAWS SDKのモジュールをバンドルしないようにします。

./lib/lambda-stack.ts

    new cdk.aws_lambda_nodejs.NodejsFunction(
      this,
      "AWS SDK for JavaScript v3 Lambda Function",
      {
        entry: path.join(
          __dirname,
          "../src/lambda/handlers/aws-sdk-js-v3-handler.ts"
        ),
        runtime: cdk.aws_lambda.Runtime.NODEJS_18_X,
        bundling: {
          minify: true,
          sourceMap: true,
          externalModules: ["@aws-sdk/*"],
          tsconfig: path.join(__dirname, "../src/lambda/tsconfig.json"),
          format: cdk.aws_lambda_nodejs.OutputFormat.ESM,
        },
        architecture: cdk.aws_lambda.Architecture.ARM_64,
        role: ec2ReadOnlyLambdaIamRole,
        logRetention: cdk.aws_logs.RetentionDays.TWO_WEEKS,
        tracing: cdk.aws_lambda.Tracing.ACTIVE,
        timeout: cdk.Duration.seconds(10),
      }
    );

npx cdk deployしてデプロイされたLambda関数を実行した結果は以下の通りです。

START RequestId: f7a67491-1b47-46f1-9eda-3a7c0aa3637a Version: $LATEST
2022-11-19T07:33:20.164Z	f7a67491-1b47-46f1-9eda-3a7c0aa3637a	INFO	event : 
{
    "instanceIds": [
        "i-0978e471511de2b3c"
    ]
}

2022-11-19T07:33:21.543Z	f7a67491-1b47-46f1-9eda-3a7c0aa3637a	INFO	
{
    "$metadata": {
        "httpStatusCode": 200,
        "requestId": "f3dfb0db-45fe-4627-a064-e98d6976eceb",
        "attempts": 1,
        "totalRetryDelay": 0
    },
    "Reservations": [
        {
            "Groups": [],
            "Instances": [
                {
                    "AmiLaunchIndex": 0,
                    "ImageId": "ami-07a53499a088e4a8c",
                    "InstanceId": "i-0978e471511de2b3c",
                    "InstanceType": "t3.micro",
                    "KeyName": "<キーペア名>",
                    "LaunchTime": "2022-11-17T12:13:28.000Z",
                    "Monitoring": {
                        "State": "disabled"
                    },
                    "Placement": {
                        "AvailabilityZone": "us-east-1a",
                        "GroupName": "",
                        "Tenancy": "default"
                    },
                    "Platform": "windows",
                    "PrivateDnsName": "ip-10-0-1-10.ec2.internal",
                    "PrivateIpAddress": "10.0.1.10",
                    "ProductCodes": [],
                    "PublicDnsName": "",
                    "State": {
                        "Code": 80,
                        "Name": "stopped"
                    },
                    "StateTransitionReason": "User initiated (2022-11-17 12:45:55 GMT)",
                    "SubnetId": "subnet-0f2a829b61fbe09df",
                    "VpcId": "vpc-08b84da1f793ed513",
                    "Architecture": "x86_64",
                    "BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/sda1",
                            "Ebs": {
                                "AttachTime": "2022-10-25T05:31:03.000Z",
                                "DeleteOnTermination": true,
                                "Status": "attached",
                                "VolumeId": "vol-074713bd4037a8d80"
                            }
                        }
                    ],
                    "ClientToken": "",
                    "EbsOptimized": true,
                    "EnaSupport": true,
                    "Hypervisor": "xen",
                    "IamInstanceProfile": {
                        "Arn": "arn:aws:iam::<AWSアカウントID>:instance-profile/AmazonSSMRoleForInstancesQuickSetup",
                        "Id": "AIPA6KUFAVPU6UWS3OMTH"
                    },
                    "InstanceLifecycle": "spot",
                    "NetworkInterfaces": [
                        {
                            "Attachment": {
                                "AttachTime": "2022-10-25T05:31:02.000Z",
                                "AttachmentId": "eni-attach-0defe9819995b4341",
                                "DeleteOnTermination": true,
                                "DeviceIndex": 0,
                                "Status": "attached",
                                "NetworkCardIndex": 0
                            },
                            "Description": "",
                            "Groups": [
                                {
                                    "GroupName": "FsxnStack-SecurityGroupofADDC6C07AC98-ANB7J1HGMO4D",
                                    "GroupId": "sg-0cd906b274d7fa365"
                                }
                            ],
                            "Ipv6Addresses": [],
                            "MacAddress": "0e:3b:42:cd:f4:d7",
                            "NetworkInterfaceId": "eni-0fb9b9d1f404ae2ef",
                            "OwnerId": "<AWSアカウントID>",
                            "PrivateDnsName": "ip-10-0-1-10.ec2.internal",
                            "PrivateIpAddress": "10.0.1.10",
                            "PrivateIpAddresses": [
                                {
                                    "Primary": true,
                                    "PrivateDnsName": "ip-10-0-1-10.ec2.internal",
                                    "PrivateIpAddress": "10.0.1.10"
                                }
                            ],
                            "SourceDestCheck": true,
                            "Status": "in-use",
                            "SubnetId": "subnet-0f2a829b61fbe09df",
                            "VpcId": "vpc-08b84da1f793ed513",
                            "InterfaceType": "interface"
                        }
                    ],
                    "RootDeviceName": "/dev/sda1",
                    "RootDeviceType": "ebs",
                    "SecurityGroups": [
                        {
                            "GroupName": "FsxnStack-SecurityGroupofADDC6C07AC98-ANB7J1HGMO4D",
                            "GroupId": "sg-0cd906b274d7fa365"
                        }
                    ],
                    "SourceDestCheck": true,
                    "SpotInstanceRequestId": "sir-ssvedt5q",
                    "StateReason": {
                        "Code": "Client.UserInitiatedShutdown",
                        "Message": "Client.UserInitiatedShutdown: User initiated shutdown"
                    },
                    "Tags": [
                        {
                            "Key": "Name",
                            "Value": "corp.non-97.net"
                        }
                    ],
                    "VirtualizationType": "hvm",
                    "CpuOptions": {
                        "CoreCount": 1,
                        "ThreadsPerCore": 2
                    },
                    "CapacityReservationSpecification": {
                        "CapacityReservationPreference": "open"
                    },
                    "HibernationOptions": {
                        "Configured": false
                    },
                    "MetadataOptions": {
                        "State": "applied",
                        "HttpTokens": "optional",
                        "HttpPutResponseHopLimit": 1,
                        "HttpEndpoint": "enabled",
                        "HttpProtocolIpv6": "disabled",
                        "InstanceMetadataTags": "disabled"
                    },
                    "EnclaveOptions": {
                        "Enabled": false
                    },
                    "PlatformDetails": "Windows",
                    "UsageOperation": "RunInstances:0002",
                    "UsageOperationUpdateTime": "2022-10-25T05:31:02.000Z",
                    "PrivateDnsNameOptions": {
                        "HostnameType": "ip-name",
                        "EnableResourceNameDnsARecord": true,
                        "EnableResourceNameDnsAAAARecord": false
                    },
                    "MaintenanceOptions": {
                        "AutoRecovery": "default"
                    }
                }
            ],
            "OwnerId": "<AWSアカウントID>",
            "ReservationId": "r-0fc771f2401c23e63"
        }
    ]
}

END RequestId: f7a67491-1b47-46f1-9eda-3a7c0aa3637a
REPORT RequestId: f7a67491-1b47-46f1-9eda-3a7c0aa3637a	Duration: 1407.61 ms	Billed Duration: 1408 ms	Memory Size: 128 MB	Max Memory Used: 128 MB	Init Duration: 1142.60 ms	
XRAY TraceId: 1-637886be-5d969b994b1f856428500f6d	SegmentId: 01303da70449b09e	Sampled: true

指定したEC2インスタンスの詳細を取得できていますね。

この時のパッケージサイズは1.2 KBでした。

externalModulesした場合のパッケージサイズ

比較するためにexternalModulesを削除しました。

この状態で再デプロイしたLambda関数のパッケージサイズは1.3 MBでした。

externalModulesしなかった場合のパッケージサイズ

パッケージ一つ追加で1.3MBだ。1,000倍だぞ1,000倍。

確かにランタイムにAWS SDK for JavaScript v3がバンドルされていそうです。

AWS CDK v2.51.0ではNodejsFunction()を使用する際に、AWS SDK for JavaScript v3がバンドルされないように指定する必要があります。早速、弊社のやまたつがランタイムにNode.js 18を選択した場合はAWS SDK for JavaScript v3がバンドルされないようにするPRを作成しています。マージされるのを期待して待ちましょう。

AWS SDK for JavaScript v2を実行してみる

次に、AWS SDK for JavaScript v2がランタイムにバンドルされていないことを確認します。

以下のようにAWS SDK for JavaScript v2を使用するLambda関数を用意します。

./src/lambda/handlers/aws-sdk-js-v2-handler.ts

import AWS from "aws-sdk";
import { Context } from "aws-lambda";

interface HandlerParameters {
  InstanceIds: string[];
}

const ec2 = new AWS.EC2({ apiVersion: "2016-11-15" });

export const handler = async (
  event: HandlerParameters,
  context: Context
): Promise<void | Error> => {
  console.log(`event : ${JSON.stringify(event, null, 2)}`);

  await ec2
    .describeInstances(event, (err, data) => {
      if (err) console.log(err, err.stack); // an error occurred
      else console.log(data); // successful response
    })
    .promise();

  return;
};

こちらのLambda関数を以下のようにデプロイします。externalModulesでAWS SDK for JavaScript v2をバンドルしないように設定します。

./lib/lambda-stack.ts

    new cdk.aws_lambda_nodejs.NodejsFunction(
      this,
      "AWS SDK for JavaScript v2 Lambda Function",
      {
        entry: path.join(
          __dirname,
          "../src/lambda/handlers/aws-sdk-js-v2-handler.ts"
        ),
        runtime: cdk.aws_lambda.Runtime.NODEJS_18_X,
        bundling: {
          minify: true,
          sourceMap: true,
          externalModules: ["aws-sdk"],
          tsconfig: path.join(__dirname, "../src/lambda/tsconfig.json"),
          format: cdk.aws_lambda_nodejs.OutputFormat.CJS,
        },
        architecture: cdk.aws_lambda.Architecture.ARM_64,
        role: ec2ReadOnlyLambdaIamRole,
        logRetention: cdk.aws_logs.RetentionDays.TWO_WEEKS,
        tracing: cdk.aws_lambda.Tracing.ACTIVE,
        timeout: cdk.Duration.seconds(10),
        memorySize: 256,
      }
    );

npx cdk deployしてデプロイされたLambda関数のパッケージサイズは1,467 Bでした。

$ aws lambda get-function \
    --function-name LambdaStack-AWSSDKforJavaScriptv2LambdaFunction1D5-pCeaP4voKN17
{
    "Configuration": {
        "FunctionName": "LambdaStack-AWSSDKforJavaScriptv2LambdaFunction1D5-pCeaP4voKN17",
        "FunctionArn": "arn:aws:lambda:us-east-1:<AWSアカウントID>:function:LambdaStack-AWSSDKforJavaScriptv2LambdaFunction1D5-pCeaP4voKN17",
        "Runtime": "nodejs18.x",
        "Role": "arn:aws:iam::<AWSアカウントID>:role/LambdaStack-AWSSDKforJavaScriptv2LambdaFunctionIAM-1BHWNJFQTSF0Y",
        "Handler": "index.handler",
        "CodeSize": 1467,
        "Description": "",
        "Timeout": 10,
        "MemorySize": 256,
        "LastModified": "2022-11-20T01:24:08.000+0000",
        "CodeSha256": "Ac8p9+U/no+pz9lD4st/OHcC5Vmpg379hYSKuTFeFNA=",
        "Version": "$LATEST",
        "VpcConfig": {
            "SubnetIds": [],
            "SecurityGroupIds": [],
            "VpcId": ""
        },
        "Environment": {
            "Variables": {
                "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1"
            }
        },
        "TracingConfig": {
            "Mode": "Active"
        },
        "RevisionId": "9b361d5e-dce2-4ec7-8484-6f757c93e0e3",
        "State": "Active",
        "LastUpdateStatus": "Successful",
        "PackageType": "Zip",
        "Architectures": [
            "arm64"
        ],
        "EphemeralStorage": {
            "Size": 512
        }
    },
    "Code": {
        "RepositoryType": "S3",
        "Location": "https://prod-04-2014-tasks.s3.us-east-1.amazonaws.com/snapshots/<AWSアカウントID>/LambdaStack-AWSSDKforJavaScriptv2LambdaFunction1D5-pCeaP4voKN17-bf62490b-72c0-438b-8f7e-04cd2f128872
    },
    "Tags": {
        "aws:cloudformation:stack-name": "LambdaStack",
        "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/LambdaStack/91617a80-6815-11ed-97b0-0a02c33c3d8b",
        "aws:cloudformation:logical-id": "AWSSDKforJavaScriptv2LambdaFunction1D52301F"
    }
}

Lambda関数は実行した結果は以下の通りです。

2022-11-20T01:24:47.094Z	undefined	ERROR	Uncaught Exception 	{"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'aws-sdk'\nRequire stack:\n- /var/task/index.js\n- /var/runtime/index.mjs","stack":["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:1000:17)","    at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)","    at async start (file:///var/runtime/index.mjs:1200:23)","    at async file:///var/runtime/index.mjs:1206:1"]}
2022-11-20T01:24:48.320Z	undefined	ERROR	Uncaught Exception 	{"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'aws-sdk'\nRequire stack:\n- /var/task/index.js\n- /var/runtime/index.mjs","stack":["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:1000:17)","    at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)","    at async start (file:///var/runtime/index.mjs:1200:23)","    at async file:///var/runtime/index.mjs:1206:1"]}
START RequestId: 8942a094-245e-4c07-bc27-e1c46c0c7db7 Version: $LATEST
Unknown application error occurred
Runtime.ImportModuleError
END RequestId: 8942a094-245e-4c07-bc27-e1c46c0c7db7
REPORT RequestId: 8942a094-245e-4c07-bc27-e1c46c0c7db7	Duration: 1299.27 ms	Billed Duration: 1300 ms	Memory Size: 256 MB	Max Memory Used: 17 MB	
XRAY TraceId: 1-637981de-55a8a3c275227d141850d2ea	SegmentId: 24211058454d730b	Sampled: true

エラーメッセージをパースしたものは以下です。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:1000:17)",
    "    at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)",
    "    at async start (file:///var/runtime/index.mjs:1200:23)",
    "    at async file:///var/runtime/index.mjs:1206:1"
  ]
}

次に、AWS SDK for JavaScript v2をバンドルするように指定します。

./lib/lambda-stack.ts

    new cdk.aws_lambda_nodejs.NodejsFunction(
      this,
      "AWS SDK for JavaScript v2 Lambda Function",
      {
        entry: path.join(
          __dirname,
          "../src/lambda/handlers/aws-sdk-js-v2-handler.ts"
        ),
        runtime: cdk.aws_lambda.Runtime.NODEJS_18_X,
        bundling: {
          minify: true,
          sourceMap: true,
          externalModules: [""],
          tsconfig: path.join(__dirname, "../src/lambda/tsconfig.json"),
          format: cdk.aws_lambda_nodejs.OutputFormat.CJS,
        },
        architecture: cdk.aws_lambda.Architecture.ARM_64,
        role: ec2ReadOnlyLambdaIamRole,
        logRetention: cdk.aws_logs.RetentionDays.TWO_WEEKS,
        tracing: cdk.aws_lambda.Tracing.ACTIVE,
        timeout: cdk.Duration.seconds(10),
        memorySize: 256,
      }
    );
test

npx cdk deployしてデプロイされたLambda関数のパッケージサイズは1.6 MBでした。

$ aws lambda get-function --function-name LambdaStack-AWSSDKforJavaScriptv2LambdaFunction1D5-pCeaP4voKN17
{
    "Configuration": {
        "FunctionName": "LambdaStack-AWSSDKforJavaScriptv2LambdaFunction1D5-pCeaP4voKN17",
        "FunctionArn": "arn:aws:lambda:us-east-1:<AWSアカウントID>:function:LambdaStack-AWSSDKforJavaScriptv2LambdaFunction1D5-pCeaP4voKN17",
        "Runtime": "nodejs18.x",
        "Role": "arn:aws:iam::<AWSアカウントID>:role/LambdaStack-AWSSDKforJavaScriptv2LambdaFunctionIAM-1BHWNJFQTSF0Y",
        "Handler": "index.handler",
        "CodeSize": 1710468,
        "Description": "",
        "Timeout": 10,
        "MemorySize": 256,
        "LastModified": "2022-11-20T01:36:41.000+0000",
        "CodeSha256": "RwfvAEh+cueVzoAlkNkeJ6k/byXDnO8VDqC1CzIIJLw=",
        "Version": "$LATEST",
        "VpcConfig": {
            "SubnetIds": [],
            "SecurityGroupIds": [],
            "VpcId": ""
        },
        "Environment": {
            "Variables": {
                "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1"
            }
        },
        "TracingConfig": {
            "Mode": "Active"
        },
        "RevisionId": "58c7a905-0bc4-4113-aca6-25645ed5dcb7",
        "State": "Active",
        "LastUpdateStatus": "Successful",
        "PackageType": "Zip",
        "Architectures": [
            "arm64"
        ],
        "EphemeralStorage": {
            "Size": 512
        }
    },
    "Code": {
        "RepositoryType": "S3",
        "Location": "https://prod-04-2014-tasks.s3.us-east-1.amazonaws.com/snapshots/<AWSアカウントID>/LambdaStack-AWSSDKforJavaScriptv2LambdaFunction1D5-pCeaP4voKN17-57f406cc-3dc1-45a3-92fb-acbea0e261dc
    },
    "Tags": {
        "aws:cloudformation:stack-name": "LambdaStack",
        "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/LambdaStack/91617a80-6815-11ed-97b0-0a02c33c3d8b",
        "aws:cloudformation:logical-id": "AWSSDKforJavaScriptv2LambdaFunction1D52301F"
    }
}

Lambda関数は実行した結果は以下の通りです。

START RequestId: a165ae09-5c8b-46d1-9dd6-df8788732592 Version: $LATEST
2022-11-20T01:39:14.414Z	a165ae09-5c8b-46d1-9dd6-df8788732592	INFO	event : {
  "InstanceIds": [
    "i-0978e471511de2b3c"
  ]
}
2022-11-20T01:39:14.996Z	a165ae09-5c8b-46d1-9dd6-df8788732592	INFO	{
  Reservations: [
    {
      Groups: [],
      Instances: [Array],
      OwnerId: '<AWSアカウントID>',
      ReservationId: 'r-0fc771f2401c23e63'
    }
  ]
}
END RequestId: a165ae09-5c8b-46d1-9dd6-df8788732592
REPORT RequestId: a165ae09-5c8b-46d1-9dd6-df8788732592	Duration: 738.45 ms	Billed Duration: 739 ms	Memory Size: 256 MB	Max Memory Used: 256 MB	Init Duration: 785.74 ms	
XRAY TraceId: 1-63798541-0b9e788c6069baf9337ba4fc	SegmentId: 334df42e2be7b6d6	Sampled: true

正しく実行できました。以上のことからAWS SDK for JavaScript v2がNode.js 18のランタイムにバンドルされていないことが分かります。

Lambda関数でNode.js 18を使用する際はAWS SDKのバージョンに気をつけよう

AWS Lambdaが Node.js 18をサポートしたアップデートを紹介しました。

AWS SDK for JavaScript v3がランタイムにバンドルされているのがやっぱり嬉しいですね。パッケージサイズ削減に繋がりそうです。

逆にv2を使用する場合は自分でバンドルする必要があります。Node.js 18にランタイムを変更する際は、どのバージョンのSDKを使用しているのか注意が必要です。

もし、Node.js 18にランタイムを変更するのであれば、AWS SDK for JavaScript v3に更新することも考えましょう。

v2からv3にすることでパッケージサイズの削減やTCP接続の再利用などパフォーマンスの向上が見込めます。

Version 3 of the SDK for JavaScript offers many benefits over version 2. Most importantly, it is modular, so your code only loads the modules it needs. Modularity also reduces your function size if you choose to deploy the SDK with your function code rather than using the version built into the Lambda runtime. Learn more about optimizing Node.js dependencies in Lambda here.

. . (中略) . .

Another difference between SDK v2 and SDK v3 is the default settings for TCP connection re-use. In the SDK v2, connection re-use is disabled by default. In SDK v3, it is enabled by default. In most cases, enabling connection re-use improves function performance. To stop TCP connection reuse, set the AWS_NODEJS_CONNECTION_REUSE_ENABLED environment variable to false. You can also stop keeping the connections alive on a per-service client basis.

Node.js 18.x runtime now available in AWS Lambda | AWS Compute Blog

aws-sdk-js-codemodというv2からv3の変換ツールもあるので、こちらもお試しください。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!