AWS SAM CLI と AWS CDK のローカルテスト連携


## [AWS SAM](https://d1.awsstatic.com/webinars/jp/pdf/services/20190814_AWS-Blackbelt_SAM_rev.pdf) とは

AWS のサーバーレスアプリケーション開発に特化した AWS CloudFromation の拡張機能です。サーバーレスアプリケーション開発を支援する [AWS SAM CLI](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/install-sam-cli.html) が提供されており Lambda 関数をローカル実行できます。

<details>
<summary>インストール方法</summary>

#### AWS SAM CLI のインストール (macOS)

```bash
brew tap aws/tap
brew install aws-sam-cli
sam --version
```

</details>

```plantuml
@startuml

title サーバーレスを取り巻く主なコンポーネント

!define AWSPuml https://raw.githubusercontent.com/awslabs/aws-icons-for-plantuml/v11.1/dist
!includeurl AWSPuml/AWSCommon.puml

!includeurl AWSPuml/AWSSimplified.puml

!includeurl AWSPuml/ApplicationIntegration/APIGateway.puml
!includeurl AWSPuml/ApplicationIntegration/AppSync.puml
!includeurl AWSPuml/ApplicationIntegration/SimpleQueueService.puml
!includeurl AWSPuml/Analytics/KinesisDataStreams.puml
!includeurl AWSPuml/Compute/Lambda.puml
!includeurl AWSPuml/Database/DynamoDB.puml
!includeurl AWSPuml/Storage/SimpleStorageService.puml

left to right direction

rectangle "外部I/F" {
  APIGateway(apiGateway, "API Gateway", "API Gateway")
  AppSync(appSync, "AppSync", "AppSync")
}

rectangle "処理ロジック" {
  Lambda(lambda, "Lambda", "Lambda")
}

rectangle "データ保持/管理" {
  DynamoDB(dynamodb, "DynamoDB", "DynamoDB")
  SimpleStorageService(s3, "S3", "S3")
  SimpleQueueService(sqs, "SQS", "SQS")
}

rectangle "ストリーム" {
  KinesisDataStreams(kinesisDataStreams, "Kinesis Data Streams", "Kinesis Data Streams")
}

appSync 0--> lambda
kinesisDataStreams 0--> lambda
lambda 0--> dynamodb
sqs 0--> lambda

@enduml
```

## [AWS CDK](https://d1.awsstatic.com/webinars/jp/pdf/services/20200303_BlackBelt_CDK.pdf) とは

AWS SAM はサーバーレスに特化かつ JSON や YAML で定義します。対して AWS CDK は Python や TypeScript など一般のプログラミング言語で記述でき、 ほとんどの AWSサービス をカバーしている CloudFormation の拡張機能です。
CloudFormation よりも一般に少ないコード量で記述ができます。

<details>
<summary>インストール方法</summary>

#### AWS CDK CLI のインストール

```bash
npm install -g aws-cdk
cdk --version
```

#### AWSアカウントのブートストラップ

CDK はデプロイ中 S3 にファイルアップロードをするためブートストラップという作業します。

```bash
# Get the account ID
aws sts get-caller-identity

# Bootstrap the account
cdk bootstrap aws://ACCOUNT-NUMBER/REGION
```

https://aws.amazon.com/jp/getting-started/guides/setup-cdk/module-two/

</details>

## AWS SAM CLI と CDK の連携とは

CDK は AWS リソースを構築するためだけのツールであるため、CDK がカバーしない、サーバーレスアプリケーションの「ローカルテスト」の機能を SAM で補完してあげる、といったイメージです。
IaC は CDK を使いたい、かつ ローカルでテストしたい ときにこの方法が選択肢になります。

![sam+cdk.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59081/aac9731d-3f89-7d92-a2e0-ac7b95b63c02.png)

## CDK with SAM: ローカルテスト

アーキテクチャは次のようになります。`cdk synth` コマンドで生成した Cfn テンプレートファイルを `SAM CLI` に食わせて実行してあげることでローカル実行を実現します。

![sam+cdk_flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59081/022c13f8-48a4-9b42-8646-7d1b966fa1ce.png)

## 開発の流れ

CDK + SAM を使った開発の流れです。

### 事前準備

```bash
cdk init app --language=typescript
# サンプルコード付き
cdk init sample-app --language=typescript

# CDKがデプロイのために使用するS3バケットを作成(対象アカウント、リージョンにつき1回だけ実施)
cdk bootstrap
```

### CDK 実装

CDK はたくさんのサンプルコードが github に公開されています。こちらを見ながら CDK を実装してみると良いでしょう。

- https://github.com/aws-samples/aws-cdk-examples

#### CloudFormation テンプレートの出力

```bash
cdk synth
```

--profile オプションで AWSプロファイル を指定すると`CDK_DEFAULT_ACCOUNT`と`CDK_DEFAULT_REGION` が利用できるようになります。（config、credentialsに設定されている値が参照されます。）

- https://docs.aws.amazon.com/cdk/v2/guide/environments.html

### サーバレスアプリケーションの作成

次のコマンドでインタラクティブにアプリケーションの作成ができます。

```bash
sam init
```

### ローカル環境で実行

#### AWS にデプロイ

ローカルの CDK アプリケーションを AWS 環境にデプロイします。

```bash
cdk deploy --require-approval never --hotswap
```

- **--require-approval** 承認が必要な場合の変更レベル。never 指定で承認不要になる
- **--hotswap** CloudFormation を介さずに直接 AWSリソース が更新される。AWSリソースに変更がなく、ソースコードのみに変更がある場合は、このオプションを付けることでソースコードのみをAWSに反映できる。（Lambda 関数、Step Functions ステート マシン、および Amazon ECS コンテナ イメージをサポート）

https://docs.aws.amazon.com/cdk/v2/guide/cli.html

#### Lambda をローカル実行する

:::note info
ローカルテストでテンプレートファイルを指定する場合、cdk.out に出力されたリソースを参照しにいきます。ローカルのソースコードの変更を反映するには再度、cdk synth を実行する必要があります。また、この方法は毎回 sam build をする必要があります。
:::

```bash
sam build --cached # --cached を付けておくとビルド時間を短縮できます
sam local invoke MyFunction --no-event --template ./cdk.out/CdkSamExampleStack.template.json
```

### CDKを使ったホットリロード

:::note info
ローカルテストではないのですが、実際の AWS 環境にデプロイした開発手法も紹介します。
:::

AWS 環境にデプロイし、ローカルのソースコードの変更だけをデプロイしてテストする場合は以下のコマンドを試すことで素早い開発を実現できます。

```bash
cdk watch --hotswap
```

#### cdk.json

もしも js ファイルを watch 対象にする場合は js が exclude されているので、削除しておく。

```diff:cdk.json
{
  "app": "npx ts-node --prefer-ts-exts bin/server.ts",
  "watch": {
    "include": [
      "**"
    ],
    "exclude": [
      "README.md",
      "cdk*.json",
      "**/*.d.ts",
-     "**/*.js",
      "tsconfig.json",
      "package*.json",
      "yarn.lock",
      "node_modules",
      "test"
    ]
  },
:
```

### SAM を使ったホットリロード

```sh
sam sync --stack-name CdkStack --watch --template ./cdk.out/CdkSamExampleStack.template.json
```

- **--stack-name** 必須。アプリケーションの AWS CloudFormation スタックの名前。
- **--watch** ローカルの変更を監視し、変更分を AWS と同期する。
- **--template** CDK テンプレートを指定。

詳細 https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-sync.html

## 参考資料

https://www.youtube.com/watch?v=kCqfvcF7ae0

https://aws.amazon.com/jp/blogs/news/aws-sam-accelerate/

https://aws.amazon.com/jp/blogs/compute/better-together-aws-sam-and-aws-cdk/