AWS CDKでAWSリソースを作成する

# 1. 諸言
AWSを初めて学び始めて半年くらいになったので、学んだことをアウトプットします。
今回はCDKでAWSリソースを実装する方法を簡潔にまとめます。

# 2. この記事でやること
AWSリソースをCDKで作成する。
- 使用する言語はTypeScript
- Lambda関数の言語はPython

使用したサービス・パッケージは以下の通りです。

| パッケージ名 | バージョン |
|:-:|:-:|
| Homebrew | 4.1.11 |
| npm | 8.19.3 |
| yarn | 1.22.19 |
| aws-cli | 2.12.0 |
| python | 3.11.3 |
| tsc | 5.1.3 |

事前準備として先に必要なライブラリ・パッケージのインストールなどは済ませます。
インストール方法などは省略します。

## 3. 導入

### 3-1. CDKの骨組みを作成する
まずは作業用のディレクトリを作成し、移動します。今回は`app`ディレクトリで作成したものとして進めます。
最初にAWSアカウントにアクセスするために`cdk bootstrap`を実行します。これは各環境ごとに一度だけ実行すれば良いです。

```
cdk bootstrap
```

次に`cdk init`コマンドでディレクトリの中にCDKの構成を自動生成します。
Template は`app`、`sample-app`、`lib`の中からどれかを作成する。今回はシンプルな`app`を選択します。
また、 TypeScript で記述したいので、`--language=typescript`オプションをつけます。
cdk コマンドについて詳しくは[こちら](https://dev.classmethod.jp/articles/aws-cdk-command-line-interface/)を参照してください。

```
$ cdk init app --language=typescript
```

コマンドが実行されるとCDKの構成が出来たことを確認する。
```:appディレクトリの中身
app/
　├ bin/
    └ app.ts
　├ lib/
    └ app-stack.ts
　├ node_module/
　├ test/
    └ app.test.ts
　├ .gitignore
　├ .npmignore
　├ cdk.json
　├ jest.config.js
　├ package-lock.json
　├ package.json
　├ README.md
　└ tsconfig.json
```

<details><summary>主要な要素の説明</summary>
    ・<code>bin</code>：アプリケーションを定義するファイル。<code>app</code>にスタックを追加することでAWSリソースをデプロイできます。<br>
    ・<code>lib</code>：スタックの定義をするファイル。このスタックはCloudFormationのスタックに相当するもので、この中にそれぞれのAWSリソースを定義します。<br>
    ・<code>package.json</code>：ライブラリパッケージに関する情報が記述されています。yarnコマンドを実行することで<code>package.json</code>に記述したライブラリを一括でインストールすることができます。<code>"scripts"</code>は実行するコマンドの定義が、<code>"dependencies"</code>は使用するライブラリのバージョン管理ができます。<br>
    ・<code>cdk.json</code>：cdkに関する情報が記述されています。cdk.jsonが存在する場合、そこに指定されたオプションがデフォルトとして使用されます。<code>"context"</code>にステージ情報とキーバリューを設定しておくことでステージに応じて処理を変えることができます。<br>
</details>

:::note info
    gitで管理するファイルを設定する。
    容量の大きなファイルやキャッシュなど必要に応じてバージョン管理しないほうが良い場合があります。
    このような場合は`.gitignore`ファイルを設定し、必要最低限のものだけをバージョン管理するようにしましょう。
    やり方は`root`配下に`.gitignore`ファイルを作成し、管理したくないものを記述するだけです。    
    `cdk init`をすると自動的に作成されています。
:::

次にターミナルで`yarn`コマンドを実行してライブラリのインストールを行います。
```
$ yarn
```
`package.json`に記載のライブラリが一括でインストールされます。

## 4. CDK で AWS リソースを定義する
ここから実際にプログラミングでリソースを定義します。詳しい記述方法は[APIリファレンス](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html)を参照してください。

### 4-1. S3バケットを作成する
今回は例として S3 バケットを作成してみます。
`lib`配下に新たな ts ファイルを作成して、その中に記述していきます。

```typescript: s3-stack.ts
import * as cdk from 'aws-cdk-lib/core';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';

export class S3Stack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    new s3.Bucket(this, 'MyFirstBucket', {
      versioned: true,
      removalPolicy: cdk.RemovalPolicy.DESTROY, // Change to RETAIN if you want to keep the bucket when deleting the stack
      autoDeleteObjects: true, // Enable to automatically delete objects when the bucket is removed
    });
  }
}
```

このコードでは、CDKを使用して新しいS3バケットを定義しています。`S3Stack`という名前のスタックに新しいS3バケットを追加し、バケットの設定項目として、バージョニングの有効化と削除ポリシーを設定します。

必要に応じて、`removalPolicy`を`DESTROY`から`RETAIN`に変更することで、スタックを削除してもバケットを保持することができます。しかし、削除されずに保持し続けることで費用が発生する可能性があるため注意が必要です。

**スタックをデプロイする**

作成したスタックをアプリケーションに追加します。
`bin`配下のtsファイルを開き、以下のように修正します。

```typescript: app.ts
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { S3Stack } from '../lib/s3-stack';

const app = new cdk.App();
new S3Stack(app, 'S3Stack');
```

CDKスタックをデプロイする前に問題ないか確認する必要があります。
確認するには`cdk synth`や`cdk diff`を用います。
・`cdk synth`：CloudFormationテンプレートの形式で出力する。
・`cdk diff`：現在のスタックとの差分を表示する。

CDKスタックをデプロイするために、ターミナルで以下のコマンドを実行しましょう。
アプリケーションが単一のスタックだけで構成されている場合、スタック名を指定する必要はありません。

```
$ yarn cdk deploy
```

これにより、定義したCDKスタックがAWS上にデプロイされます。
デプロイが完了すると、AWSコンソールでS3バケットを確認できます。

### 4-2. API Gateway、Lambda、DynamoDB を作成する


API Gateway、Lambda、DynamoDBを作成し、APIを呼ぶとLambda関数が実行され、DynamoDBから取得した値をレスポンスとして返す方法を追加します。

まず、API Gateway、Lambda、DynamoDBをCDKを使用して定義します。

```typescript: app-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';

export class AppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // DynamoDB Table
    const table = new dynamodb.Table(this, 'Table', {
      partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
    });

    // Lambda Function
    const handler = new lambda.Function(this, 'Lambda', {
      runtime: lambda.Runtime.PYTHON_3_10,
      handler: 'index.handler',
      code: lambda.Code.fromAsset("lambda"),
    });

    // Grant DynamoDB read permission to Lambda
    table.grantReadData(handler);

    // API Gateway
    const api = new apigateway.RestApi(this, 'Api');
    const integration = new apigateway.LambdaIntegration(handler);
    api.root.addMethod('GET', integration);
  }
}

```

このコードでは、CDKを使って以下のリソースを定義しています：

- DynamoDBテーブル（`Table`）: 主キーとして`id`を持つ単純なテーブル
- Lambda関数（`Lambda`）: `index.handler`をエントリーポイントとして持つ`python3.10`のLambda関数。ここでは、DynamoDBからデータを読み取る操作を行い、取得したデータをAPIのレスポンスとして返す。
- API Gateway（`Api`）: Lambda関数を呼び出すためのREST APIを提供する。Lambda関数をAPIのルートに統合し、GETメソッドを定義している。

**CDKスタックをデプロイする**

まずはアプリケーションにスタックを追加しましょう。

```typescript: app.ts
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { AppStack } from '../lib/app-stack';
import { S3Stack } from '../lib/s3-stack';

const app = new cdk.App();
new S3Stack(app, 'S3Stack');
new AppStack(app, 'AppStack');
```

追加できたら、先程と同様にCDKスタックをデプロイするコマンドを実行します。
複数のスタックが存在する場合はスタックidを指定してデプロイします。

```
$ yarn cdk deploy AppStack
```

一度にすべてのスタックをデプロイしたい場合は`--all`オプションをつけて実行します。

```
$ yarn cdk deploy --all
```

**リソースを確認する**

デプロイが完了したら、API Gatewayのエンドポイントを使用してAPIを呼び出します。GETリクエストを送信すると、Lambda関数が実行され、DynamoDBから取得したデータがレスポンスとして返されます。必要に応じて、DynamoDBの操作やLambda関数の処理を変更することで、データを取得・更新などカスタマイズすることができます。

**CDKスタックを削除する**

テストが終わり使用しなくなったCDKスタックは削除しておきましょう。

```
$ yarn cdk destroy --all
```

これにより、デプロイしたCDKスタックに関連するAWSリソースが削除されます。

## 5. まとめ

この記事では、CDKを使用してAWSリソースをプログラムで作成し、デプロイおよび削除する方法を簡潔にまとめました。CDKを活用することで、設定の変更・AWSリソースの作成と削除が容易になり、管理がより効率的に行えます。