AWS CDK で Typescriptで記述したLambdaをデプロイする方法
まずは結論から
aws-cdk-libモジュールのaws_lambda_nodejsを使います
フォルダ構成
lib
└── sample-cdk-stack.ts
lambda
└── post-item.ts
import {
aws_lambda_nodejs
} from "aws-cdk-lib"
import {
Runtime
} from "aws-cdk-lib/aws-lambda";
export class SampleCdkStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// ~~ DynamoDBの定義などいろいろ省略 ~~
const postItemFunction = new aws_lambda_nodejs.NodejsFunction(this, "postItemFunction", {
entry: path.join(__dirname, '../lambda/post-item.ts'),
runtime: Runtime.NODEJS_16_X,
handler: 'handler',
environment: {
TABLE_NAME: dynamoTable.tableName,
PRIMARY_KEY: "id",
},
});
}
}
cdk deploy
を実行すると、TSのコンパイルが走ったような表示が出た後、無事にデプロイされます。
経緯
- 参考コードを見ているとデプロイするLambdaがTSで記述されている
- 特に何も設定をせずにそのままデプロイしてるので、真似してデプロイしてみる
- デプロイ自体は成功するが、Lambdaの実行をすると、このようなエラーが出る
"errorMessage": "Error: Cannot find module 'post-item'\nRequire stack:\n- /var/runtime/index.mjs"
- エラー内容的に、Lambdaの内部でpost-itemファイルを探しているが、見つからないというエラーの様子
- TSファイルをそのまま上げているのがまずいんじゃない?
- JSにコンパイルしてから上げる方法を探す
-
aws_lambda_nodejs.NodejsFunction
を使えばいいらしい - 出来たけど懸念事項がある
詳細
参考コードを見ているとデプロイするLambdaがTSで記述されている
こちらのコードを参考にさせていただきました
現在のAWS CDKはVersion2で、参考コードがVersion1なので、書き換えながら進めました
Lambda, APIGateway, DynamoDBの構成作成が非常に捗りました、ありがとうございます
エラーが出ていた時のコード、こんな感じ
(参考コードから少し変えています)
import {
Runtime, Function, AssetCode
} from "aws-cdk-lib/aws-lambda";
export class SampleCdkStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// ~~ DynamoDBの定義などいろいろ省略 ~~
const postItemFunction = new Function(this, "postItemFunction", {
code: new AssetCode("lambda"),
handler: "post-item.handler",
runtime: Runtime.NODEJS_16_X,
environment: {
TABLE_NAME: dynamoTable.tableName,
PRIMARY_KEY: "id",
},
});
}
}
デプロイ自体は成功するが、Lambdaの実行をするとエラーが出る
デプロイ自体は成功ですが、Lambdaのテスト実行を行うとエラーが出てしまいました
こんなエラーです
(CloudWatch Logs)
{
"errorType": "Runtime.ImportModuleError",
"errorMessage": "Error: Cannot find module 'post-item'\nRequire stack:\n- /var/runtime/index.mjs",
"stack": [
"Runtime.ImportModuleError: Error: Cannot find module 'post-item'",
"Require stack:",
"- /var/runtime/index.mjs",
" at _loadUserApp (file:///var/runtime/index.mjs:726:17)",
" at async Object.module.exports.load (file:///var/runtime/index.mjs:741:21)",
" at async file:///var/runtime/index.mjs:781:15",
" at async file:///var/runtime/index.mjs:4:1"
]
}
Lambdaは「ハンドラー」の設定で、実行するファイルと関数を決定しているようで、Node.jsのランタイムだと「ハンドラー」を hoge.handlerに設定していたら、 hoge.js
ファイルのhandler関数を実行するようです
マネジメントコンソールだと、こんな感じ
(index.jsのhandler関数を実行する)
aws_lambda_nodejs.NodejsFunction を使えばいいらしい
「aws-cdk-libモジュールのaws_lambda_nodejsを使えばいいらしい」
と、調べていると出てきたのでこちらを試してみました
それで出来上がったのが、最初にも掲載したこちらのコードになります
import {
aws_lambda_nodejs
} from "aws-cdk-lib"
import {
Runtime
} from "aws-cdk-lib/aws-lambda";
export class SampleCdkStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// ~~ DynamoDBの定義などいろいろ省略 ~~
const postItemFunction = new aws_lambda_nodejs.NodejsFunction(this, "postItemFunction", {
entry: path.join(__dirname, '../lambda/post-item.ts'),
runtime: Runtime.NODEJS_16_X,
handler: 'handler',
environment: {
TABLE_NAME: dynamoTable.tableName,
PRIMARY_KEY: "id",
},
});
}
}
出来たけど懸念事項がある
ひとまずデプロイして実行も出来ましたが、気になる点がありました
それは、 new Function
を使っているときと new aws_lambda_nodejs.NodejsFunction
を使っているときでパラメータが異なっていること
aws_lambda_nodejs.NodejsFunction
が後追いで作られた機能だとしたら、Function
側にパラメータを寄せる気がします
見ていただきたいのは後半部分の差分です
import {
- Runtime, Function, AssetCode
+ aws_lambda_nodejs
+} from "aws-cdk-lib"
+import {
+ Runtime
} from "aws-cdk-lib/aws-lambda";
+ import * as path from 'path'
export class SampleCdkStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// ~~ DynamoDBの定義などいろいろ省略 ~~
- const postItemFunction = new Function(this, "postItemFunction", {
- code: new AssetCode("lambda"),
- handler: "post-item.handler",
+ const postItemFunction = new aws_lambda_nodejs.NodejsFunction(this, "postItemFunction", {
+ entry: path.join(__dirname, '../lambda/post-item.ts'),
+ handler: 'handler',
runtime: Runtime.NODEJS_16_X,
environment: {
TABLE_NAME: dynamoTable.tableName,
PRIMARY_KEY: "id",
},
});
}
}
Functionでは code
NodejsFunctionでは entry
という設定値になっています
パラメータの値も若干変わってしまいました
ここが気になるので、もっと良いやり方がありそう、と思いつつも現状分かっているところまで記事化しました
2022/08/27 追記
コメント頂いたので、追記します!ありがとうございます。
aws-lambda-node.js
は Node.js製のLambdaを構築するために特化したパッケージです。
aws-lambda-python
やaws-lambda-go
と、それぞれに特化したパッケージがあります。
従来の aws-cdk-lib/aws-lambda
の Function
では code
でコードの配置されているフォルダを指定する必要があります。
こちらだと、該当のソースがあるフォルダごとLambdaにデプロイされていました。
NodejsFunction
では entry
で単一のファイルを指定できるため、より使いやすくなっている、という感じのようです。
参考記事
NodejsFunction周りで参考にした記事がいくつかあるので、気になる方はご覧くださいー!
Discussion
こんにちは!
NodejsFunction
はFunction
をNode.js向けに抽象化したものなので、パラメータもより便利な形に変わってます記事内のコードの通り、
code
ではなくentry
を指定する形で大丈夫ですよーAssetCode
を意識せずとも、ただファイルのパスだけ指定すれば動くようになっていますコメントありがとうございます!
コメント頂いたことで、改めて他記事を漁り
NodejsFunction
への理解を深めることができました。確かに、
Function
からの互換性というよりも、entry
の形式でファイルパスをそのまま指定する方が判りやすいですね。記事に参考記事含めて色々追記させていただきますー!