🍢

AWS CDKがなにもわからないので、勉強の為にAPI GatewayとLambdaをデプロイしてみた

2024/03/18に公開

はじめに

CDKを知るために、なるべく簡単なコードでAPI Gateway + LambdaのAPIを作りながら勉強してみました。半年後の自分が内容を忘れててもこれを読めば完全に理解できるように記録を残します。
間違いなどあれば優しくコメントで指摘いただけると助かります。

そもそもAWS CDKとは?

そもそもAWS CDKとはなにか。AI(Gemini)に聞いてみました。

AWS CDKとはなんですか?

AWS CDK とは

AWS CDK は、最新のプログラミング言語を使用してクラウドインフラストラクチャをコードとして定義し、それを AWS CloudFormation を通じてデプロイするためのオープンソースのソフトウェア開発フレームワークです。

主な特徴:

  • 使い慣れたプログラミング言語を使用できる: TypeScript、Python、Java、C# などの最新言語でコードを書くことができます。
  • コードとしてインフラストラクチャを定義: インフラストラクチャをテンプレートではなくコードとして記述することで、バージョン管理やコラボレーションが容易になります。
  • 安全で堅牢なインフラストラクチャ: AWS CDK は、AWS のベストプラクティスに基づいて構築されており、安全で堅牢なインフラストラクチャを構築するのに役立ちます。
  • 高速なデプロイ: AWS CDK は、CloudFormation を使用してインフラストラクチャをデプロイするため、高速かつ効率的にデプロイできます。

AWS CDK のメリット:

  • 生産性の向上: コードとしてインフラストラクチャを定義することで、手動による作業を減らし、生産性を向上させることができます。
  • コストの削減: インフラストラクチャを効率的にデプロイすることで、コストを削減することができます。
  • セキュリティの強化: 安全で堅牢なインフラストラクチャを構築することで、セキュリティを強化することができます。
  • コラボレーションの向上: コードとしてインフラストラクチャを定義することで、チームメンバー間のコラボレーションを向上させることができます。

AWS CDK のユースケース:

  • 新規の AWS インフラストラクチャの構築
  • 既存の AWS インフラストラクチャの管理
  • CI/CD パイプラインの構築
  • サーバーレスアプリケーションの開発

AWS CDK の詳細:

AWS CDK は、AWS インフラストラクチャを構築、管理、デプロイするための強力なツールです。 使い慣れたプログラミング言語を使用してコードとしてインフラストラクチャを定義することで、生産性、コスト、セキュリティ、コラボレーションを向上させることができます。

その他の質問:

  • AWS CDK は CloudFormation とどう違うのですか?

AWS CDK は、CloudFormation を抽象化したフレームワークです。 AWS CDK を使用すると、CloudFormation テンプレートを直接記述することなく、コードとしてインフラストラクチャを定義できます。

  • AWS CDK はどの言語で記述できますか?

AWS CDK は、TypeScript、Python、Java、C# などの最新言語で記述できます。

  • AWS CDK を使用するには何が必要ですか?

AWS CDK を使用するには、AWS アカウントと、Node.js 12 以降が必要です。

AWS CDK の学習を始めるには、以下のリソースを参照してください:

CDKやってみた

CDKのはじめ方は、こちらのドキュメントに記載があります。
https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/hello_world.html

プロジェクトの初期化

とりあえずCDKのプロジェクトを初期化してみます。

npx cdk init -l typescript

以下のような構成が出来上がりました。

.
├── README.md
├── bin
│   └── simple-cdk-sample.ts
├── cdk.json
├── jest.config.js
├── lib
│   └── simple-cdk-sample-stack.ts
├── package-lock.json
├── package.json
├── test
│   └── simple-cdk-sample.test.ts
└── tsconfig.json

Typescriptを指定したので.tsがソースコードになります。testはそのままテストコードなので、cdkの実態はbinlibの配下に書くということになります。
いまいちソースコードが置いてあるとは思えないフォルダ名ですね。さっそく良く分からなくなってきたので、CDKの仕組みを確認してみます。

CDKの構造

https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/home.html
CDKについて知るために、開発者ガイドを見てみました。

こちらの図から分かるように、CDKは、App -> Stack -> Constructの3層構造[1]になっているようです。CDKのStackがCFnのStackに相当しますので、Stackに作りたいリソースのConstructを追加していくことになります。
そして、先程のフォルダ構成に当てはめると、

  • App
    • bin配下に書く
  • Stack
    • lib配下に書く
  • Construct[2]
    • 自力で書いても良いけど、基本は公式が用意したものを使えばOK

ということになるようです。

フォルダ構成をシンプルにしてみる

さて、本格的な開発ならフォルダ構成の階層化や標準化は必須ですが、今回は最小構成でやってみるだけなのでフラットな構成でも別にいいでしょう。ということでbinとlibを消しました。AppなのにbinとかStackなのにlibとか言われても混乱してしまいますし。[3]
また、製品開発ならテストは当然必要ですが、今回はそこまでしないのでテスト関連も消しました。

ですが、単純に消し去るとAppとStackがなくなってしまうので、直下にtsファイルを追加して書いておきました。

simple-cdk-sample.ts
import * as cdk from 'aws-cdk-lib';

const app = new cdk.App();
const stack = new cdk.Stack(app, "SimpleCdkSampleStack", {});

また、cdk.jsonのAppへの参照を変更しておきます。

cdk.json
- "app": "npx ts-node --prefer-ts-exts bin/simple-cdk-sample.ts",
+ "app": "npx ts-node --prefer-ts-exts simple-cdk-sample.ts", 

これで、ファイル構造がシンプルになりました!

.
├── README.md
├── cdk.json
├── package-lock.json
├── package.json
├── simple-cdk-sample.ts
└── tsconfig.json

Lambdaのコードを書く

本格的にCDKのコードを書く前に、雑にLambdaのコードを書いておきます。

lambda/index.ts
export async function handler(event: any) {
  return {
    statusCode: 200,
    body: JSON.stringify('Hello Lambda'),
  };
};

Constructについて調べてみる

あとは、CDKでLambdaをAPI Gatewayを構築するコードを書くだけです。
既にAppとStackはコードに書いたのでConstructを使えばよいわけです。逆に言うと、LambdaやAPI GatewayなどのAWSのリソースに対応したクラスがConstructだということになります。

せっかくなのでConstructをもう少し調べてみます。
https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/constructs.html
開発者ガイドによるとConstructは更に3階層[4]あるようです。正確な定義はドキュメントを読んでいただければよいですが、ざっくり書いてしまうとこんな感じだと思います。たぶん。

  • L1
    • 最小の単位
  • L2
    • 一般的に使われるAWSリソースの単位
  • L3
    • 複数のリソースを組み合わせて便利に使えるようにしたやつ

どういうことかというと、つまりL2を使うのが一般的だけどL3のConstructを探してくればより楽に書けるということです!

LambdaとAPI Gatewayを構築する

ということで、API GatewayとLambdaをまとめて構築するL3のConstructを探しました。
https://github.com/awslabs/aws-solutions-constructs/tree/main/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda
ありました。ですので、使いました。[5]
デフォルトだとAPI Gatewayに認証が付くのですが今回は認証無しにしました。Deploy時にめっちゃ警告出ますが気にしないことにします。

npm i @aws-solutions-constructs/aws-apigateway-lambda
simple-cdk-sample.ts
import * as cdk from 'aws-cdk-lib';
+ import { ApiGatewayToLambda } from '@aws-solutions-constructs/aws-apigateway-lambda';
+ import * as lambda from 'aws-cdk-lib/aws-lambda';

const app = new cdk.App();
const stack = new cdk.Stack(app, "SimpleCdkSampleStack", {});

+ const apiToLambda = new ApiGatewayToLambda(stack, 'ApiGatewayToLambda', {
+   lambdaFunctionProps: {
+     runtime: lambda.Runtime.NODEJS_20_X,
+     handler: 'index.handler',
+     code: lambda.Code.fromAsset(`lambda`)
+   },
+   apiGatewayProps: {
+     restApiName: 'SimpleCdkSampleApi',
+     defaultMethodOptions: {
+       authorizationType: 'NONE',
+     },
+   },
+ });

以上で完成です。

デプロイしてみる

まずはビルド

npm run build

そしてデプロイ

npx cdk deploy

ブラウザでAPI GatewayのURLにアクセス

無事にAPI Gateway + LambdaをCDKでデプロイ出来ました!

最後に

API Gateway + Lambdaを実際に構築することで少しはCDKを理解できたような気がします。
CDKはAPP+Stack+Constructで3層で構成されます。コードの実装(Lambdaの中身は除く)を各1ステップの計3ステップで書けたので、最初に目標にしたなるべく簡単なコードを無事に達成出来たと言ってよいでしょう。

作ったものはGitHubにあげておきます。
https://github.com/k-ibaraki/simple-cdk-sample

脚注
  1. CDKは3層構造と書いたのですが、実際のコードを見るとAppもStackもConstructを継承しているんですよね。でも、AppはStackを継承しているわけではないです。オブジェクトのtree構造の関係性は3層構造ですが、クラス同士の汎化の関係性はそれとは別で結構複雑なのですよね。 ↩︎

  2. initした直後のコードだと、Constructが出てくるのはStackのコンストラクターの引数の型なんですよね。その引数に代入されているのはAppです。AppがConstructを継承していることを知らないと混乱します。そもそもコンストラクターとConstructという似た言葉が並んでいる時点で分かりにくいとも思ったので、今回は構成をぶっ壊してコードを1ファイルに集約してみました。あと、コンストラクターに長々とコード書くのは良くないと思うんですよね、個人的には。 ↩︎

  3. 個人的にはフォルダ名もapp,stack,constructにしたほうが分かりやすいと思うんですけど、なんでbinlibなのでしょうか?理由を知っている人がいたら教えて欲しいです。 ↩︎

  4. 前述の通りAppとStackもConstructを継承しているので、AppやStackもConstructと言えるのですよね。一方でConstructはL3までしかないのですがAppやStackがL3かと言われると違和感しかないんですよね。L4がStack、L5がAppの方が分かりやすいと思うのですが何か不都合があるのでしょうかね? ↩︎

  5. LambdaとApiGatewayを同時に作るやつを探したら本当にあって驚きました。探してみるものですね。正直なところaws_lambda_nodejs+LambdaRestApiの組み合わせの方が実際には使いやすいと思いますが、記事的には分かりやすいL3があって助かりました。LambdaRestApiはL3かL2か微妙なラインなので説明が難しくなるんですよね。コードのステップ数も増えますし。 ↩︎

NCDCエンジニアブログ

Discussion