初めての AWS CDK です。AWS 関連は経験がまだ全然なくやったことのログ的なエントリーとなります。
AWS CDK って何?
AWS Cloud Development Kit (AWS CDK) は、使い慣れたプログラミング言語を使用してクラウドアプリケーションリソースを定義するためのオープンソースのソフトウェア開発フレームワークです。
AWS クラウド開発キット – アマゾン ウェブ サービス
AWS CDK コマンドのインストール
$ npm i -g aws-sdk $ cdk --version 2.25.0 (build ae1cb4b)
⚠ sdk init
でテンプレートを作成する際に空ディレクトリでないとエラーになったので aws-sdk
は global にインストールした
CDK でテンプレートの作成
cdk init
コマンドでリソースの設定を記述するテンプレートが生成される
# プロジェクトのディレクトリを作成 ※ディレクトリ名が Stack 名などになる $ mkdir cdk-sample && cd cdk-sample # テンプレートの生成 $ cdk init --language typescript
Stack の追加
📝 @aws-cdk/aws-lambda
と aws-cdk-lib/aws-lambda
の違いって何?
調べていると @aws-cdk
のパッケージを使用している例がよく出てくるが、VSCode の補完では aws-cdk-lib
の方になるので何が違うの????ってなった
@aws-cdk
は v1.x 系
@aws-cdk
は v1.x 系 で現行の v2.x 系は aws-cdk-lib
トノコト。
cdk
のヴァージョンが 2.25.0
なので aws-cdk-lib
の方を使えば良さそう
参考にしている記事が v1.x 系の場合は違いを公式ドキュメント(AWS CDK · AWS CDK Reference Documentation)を参考に適時調べるの良さそう
Lambda の設定
Stack の設定ファイルは lib/
内にある
lib/cdk-sample-stack.ts
import { Stack, StackProps } from 'aws-cdk-lib'; + import { Runtime } from 'aws-cdk-lib/aws-lambda'; + import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'; import { Construct } from 'constructs'; export class CdkSampleStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); + // Lambda + const lambda = new NodejsFunction(this, 'lambda', { + entry: 'lambda/index.ts', // lambda 関数のエントリーポイント + handler: 'handler', // 実行する関数名 + runtime: Runtime.NODEJS_16_X, + }); } }
📝
- Lambda 関数を TypeScript で作成する場合は
aws-cdk-lib/aws-lambda-nodejs
のNodejsFunction
を使うNodejsFunction
は自動的に JS ファイルにコンパイルしたものを Lambda にデプロイしてくれる
aws-cdk-lib/aws-lambda
のFunction
は Lambda 関数を JavaScript で作成した場合に使用する
API Gateway の設定
lib/cdk-sample-stack.ts
import { Stack, StackProps } from 'aws-cdk-lib'; + import { LambdaRestApi } from 'aws-cdk-lib/aws-apigateway'; import { Runtime } from 'aws-cdk-lib/aws-lambda'; import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'; import { Construct } from 'constructs'; export class CdkSampleStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); // Lambda const lambda = new NodejsFunction(this, 'lambda', { entry: 'lambda/index.ts', handler: 'handler', runtime: Runtime.NODEJS_16_X, }); + // API Gateway + const api = new LambdaRestApi(this, 'REST_API', { + handler: lambda, + }); } }
Lambda 関数の作成 (TypeScript)
Lambda 用の型をインストール
$ npm i -D @types/aws-lambda
Lambda 関数は Stack で lambda/index.ts
にしたのでディレクトリとファイルを作成する
lambda/index.ts
import { APIGatewayEventRequestContextV2, APIGatewayProxyEventV2, APIGatewayProxyResultV2, } from 'aws-lambda'; export const handler = async ( event: APIGatewayProxyEventV2, context: APIGatewayEventRequestContextV2, ): Promise<APIGatewayProxyResultV2> => { const responseBody = { message: 'Hello lambda!', }; return { statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(responseBody), }; };
Hello lambda!
を返すだけのシンプルな関数を作成
型も APIGatewayProxyEvent
と APIGatewayProxyEventV2
のように V2 があるものと無いものがサジェストされる。CDK v2.x 系なので V2 がある方にすれば良さそう (サジェストいい感じになってほしい〜)
🚀 Deploy
下準備 Bootstrap
$ cdk bootstrap --profile <USER NAME>
CDK Stack のデプロイに必要な S3 バケットを準備したりしてくれるらしい
実行したけど AWS コンソールをみてもバケットが新規にできてなかったので合っているのか判断できてません
デプロイ Deploy
$ cdk deploy --profile <USER NAME> … Do you wish to deploy these changes (y/n)? y … ✨ Deployment time: 89.97s Outputs: CdkSampleStackStack.RESTAPIEndpoint0000000 = https://XXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/ Stack ARN: arn:aws:cloudformation:ap-northeast-1:XXXX:stack/CdkSampleStackStack/XXXXX-XXXX-XXXX-XXXX-XXXXXX ✨ Total time: 126.45s
デプロイされる内容がつらつら出力された後に本当にデプロイするかきかれるので y
を入力
後は自動で AWS にデプロイされていく
Lambda の確認
デプロイの最後に出力された RESTAPIEndpoint の URL を curl で叩いて Hello lambda!
が返ってきていればOK
$ curl https://XXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/ {"message":"Hello lambda!"}
デプロイされている Lambda 関数
AWS console の Lambda からデプロイされたコードを見ると JavaScript にビルドされた状態でデプロイされていることが確認できました
// index.js var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { handler: () => handler }); module.exports = __toCommonJS(src_exports); var handler = async (event, context) => { const responseBody = { message: "Hello lambda!" }; return { statusCode: 200, headers: { "Content-Type": "application/json" }, body: JSON.stringify(responseBody) }; }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { handler });
プロジェクトの削除
cdk destroy
コマンドで作成したリソース群を削除できる
$ cdk destroy --profile <USER NAME>
所感
超シンプルですが、なんとか TypeScript で Lambda をデプロイすることができました。
かなり前に Serverless
ってフレームワークを使って AWS 上に Lambda を作成しましたが、その際は AWS のコンソールに入って手動でバケット作ったり色々とやったのでコードベースで自動化されるのはとても良い仕組みだなと感じました。
CLI で勝手に AWS 上に何かができるの、どこに何ができているのか初学者には把握が難しい。
今回 S3 にバケットが作成されなかったが、それが正しいのかどうかも判断できてません。(コードがシンプルだったからバケット不要になったのかな?)
AWS のドキュメントにベストプラクティスとか載ってるけど、まだ理解が追いついていないので追々…
[参考]
- 【コードでインフラ定義】CDKという異次元体験をさくっとやるのに便利なAWS公式Workshopの紹介 | DevelopersIO
- AWS入門 - AWS CDK 使ってみる
- AWS CDKにLambda関数を数秒でデプロイするhotswap deployments機能が追加されました
- CDKを使って、一つのLambda関数でAPI設計してみた | DevelopersIO
- cdk コマンドの機能を 実際に叩いて理解する 【 AWS CDK Command Line Interface 】 | DevelopersIO
- Lambda Function URLs を AWS CDK で設定する (v2.21.0 以降) | DevelopersIO
- AWS CDK で TypeScript で実装した Lambda 関数をデプロイする (NodejsFunction)|まくろぐ
- class NodejsFunction (construct) · AWS CDK