aws-cdkのv2が来たのでドキュメントを読んでみたメモ

## 概要
[aws cdk v2](https://aws.amazon.com/jp/about-aws/whats-new/2021/12/aws-cloud-development-kit-cdk-generally-available/)の安定板が公開されたので、ドキュメントをGoogle日本語翻訳しながら読んでみる。
引用と感想を適宜挟んでいく。


## What is the AWS CDK?
[AWS CDKとは何ですか？](https://docs.aws.amazon.com/cdk/v2/guide/home.html)

以下の図が分かりやすい。
CloudFormation (IaC) を型の助けを借りつつコードで書けるようにしたものという理解。
![](https://docs.aws.amazon.com/cdk/v2/guide/images/AppStacks.png)

[追加のドキュメントとリソース](https://docs.aws.amazon.com/cdk/v2/guide/home.html#additional_docs)は充実しているように見える。どれから読もうか。

## Getting started with the AWS CDK
[入門](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html)。

* CDKの対象ユーザ
  * [IAM](https://aws.amazon.com/jp/iam/)を扱った経験があること
  * CDKで使うプログラミング言語の経験があること(Typescript,Python,Java,C#)
  * [CloudFormation](https://aws.amazon.com/jp/cloudformation/)の経験があるとなおよし
  * cdkを動かす環境で、`aws cli`で使うAWSクレデンシャルがすでにあること
     * [aws configure](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/welcome-examples.html)が設定済で、`aws s3 ls`でバケットを見れる程度と理解

### 重要な概念: コンストラクト

概念|意味
--|--
Construct|S3バケットなどの具体的なAWSリソースを定義。クラス（型）として表現される。

コンストラクトには以下の種類がある

略称|種別|意味
--|--|--
L1|AWS CloudFormation-only|AWSCloudFormationによって定義されたリソースタイプに直接対応.AWS CloudFormation仕様から自動的に生成.常に`Cfn`で始まる名前が付く。(例: S3の場合`CfnBucket`)
L2|Curated |L1リソースをカプセル化し、適切なデフォルトとベストプラクティスのセキュリティポリシーを提供したもの。特定のユースケースに対応し、インフラストラクチャ開発を簡素化する（例：S3の場合、`Bucket`)
L3|Patterns |特定のユースケース向けにAWSアーキテクチャ全体を作成するための複数のリソースを宣言。構成はパラメータに要約される。

`Construct`の基本クラスは、v1では`cdk-core`モジュールにあった。v2では`constructs`モジュールに移動している。これは、`Construct`クラスは`aws-cdk`以外にも`terraform-cdk`や`kubernetes-cdk`でも使われるようになったため。

### ブートストラップ
[Asset](https://docs.aws.amazon.com/cdk/v2/guide/assets.html)をアップロードする先のコンテナ(S3バケット)を、デプロイ先のアカウント・リージョンに作成すること。

[Asset](https://docs.aws.amazon.com/cdk/v2/guide/assets.html)とは、AWSLambda関数やDockerイメージなど、スタックとともにデプロイされる外部ファイルのこと。CDKはAssetをコンテナにアップロードして、デプロイ中にCloudFormationで利用する。

### AWS CDK Toolkit (CLI)
AWS CDK Toolkitは、AWSCDKアプリとやり取りするために使用するメインツール。
コマンドラインインターフェイス（CLI）とも呼ばれる。
コードを実行し、AWSCloudFormationテンプレートを生成してデプロイする。
また、展開、差分、削除、およびトラブルシューティングの機能もある。
詳細は[AWS CDK Toolkit](https://docs.aws.amazon.com/cdk/v2/guide/cli.html)を参照

### NextSteps

[次のステップ](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_next_steps)
[ワークショップ](https://cdkworkshop.com/)はcdk v1を最初に触ったときに手を動かして概念を知るのに役になった。ほとんど同じかな？
[Construc Hub](https://constructs.dev/search?q=&cdk=aws-cdk&cdkver=2&sort=downloadsDesc&offset=0)はコンストラクトの定義を集めた場所かしら。困ったら参照するドキュメントとして覚えておいたほうがよさそう。

## Your first AWS CDK app
[最初のAWSCDKアプリ](https://docs.aws.amazon.com/cdk/v2/guide/hello_world.html)。
アプリをデプロイするまでを解説している。とりあえず読み進めたいので、自分は手を動かすのはスキップ。initで作成される内容のv1との比較だけやってみた。[v1とv2の比較](https://github.com/hibohiboo/aws-cdk-v2/commit/f0c9b7ac23e3beecbfbc95aef039469f4efc47a1)。
大きな違いはないように見える。

そもそもv1の最新のinitが作られるファイルが自分が1年前にinitで作ったファイルと違っていた。

### Add an Amazon S3 bucket
最初の[コンストラクト](https://docs.aws.amazon.com/cdk/v2/guide/constructs.html)なので、解説が入っている。大事そうなので抜粋。

```ts:lib/hello-cdk-stack.ts
import * as cdk from 'aws-cdk-lib';
import { aws_s3 as s3 } from 'aws-cdk-lib';

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

    new s3.Bucket(this, 'MyFirstBucket', {
      versioned: true
    });
  }
}
```

`new s3.Bucket(scope, id, props)`の3つのパラメータについて詳しく見ている。

パラメータ|概要|説明
--|--|--
scope|スタックのスコープを指定|コンストラクト内にコンストラクトを定義して階層を作ることもできる。例ではスタックが親であることを指定(this=Stack)
id|AWSCDKアプリ内のリソースの論理ID|デプロイ全体でリソースを一意に識別する。定義を変更したときCDKがリソースを更新するために必要。スコープ内で一意である必要がある。作成するリソースにはこのIDと別の名前をつけることもできる（例： `bucketName`プロパティに指定)
props|リソースに設定するプロパティ|例では`versioned=true`。バケット内のファイルのバージョン管理を有効にするプロパティを設定

### Destroying the app's resources
> バケットを変更しなかった場合RemovalPolicy、スタックの削除は正常に完了しますが、バケットは孤立します（スタックに関連付けられなくなります）。

ノートに結構大事なことが書いてあるので覚書。
設定によっては、Stackで定義したコンストラクトが削除されないパターンがある。
意図しないリソースが残っていないか、stackをdestroyした後は確認しておいたほうがよいかもしれない。

## Concepts
ざっくり、気になったら読むとかでも良さそう。
初心者（今後、忘れ去った自分）が読んでおくとよいものに○をつけておく。

項目|初|感想
--|--|--
[Constructs](https://docs.aws.amazon.com/cdk/v2/guide/constructs.html)|○|L1とかL2の説明があるので、CDK触ったことなければ読んで損はない。
[Apps](https://docs.aws.amazon.com/cdk/v2/guide/apps.html)|○|ライフサイクルが分かる
Stacks||デプロイ単位、という以上のことはテクニカルなことをするときに使いそう。
Environments||複数環境を一気に定義とかの参考かな
Resources||他のStackで作ったリソースにアクセスしたくなったら読むと良さそう
Identifiers||重要な概念や最初のAppでIDの大事なことは説明されているので、より詳細を知りたくなれば
Tokens||ちょっと凝ったことするときに見るとヒントになるかも
Parameters||一般にオススメしないらしい。既存のCloudFormationの移行とかだと見るかも？
Tagging||とりあえずタグはつけておいたほうがいいと思うが、最初に必須とまでは。。。
Assets||重要な概念のブートストラップで概要は十分。v2でs3以外も選択肢に入ったので気になる人は
[Permissions](https://docs.aws.amazon.com/cdk/v2/guide/permissions.html)|○|初心者が最初にハマりがちな権限。最初は意味が分からなくていい。後でそういえば、、となりそうな情報が書かれている。
Context||Runtime context。StackやConstrutに関連付けるキーと値のペア。cdk.jsonやcdk.context.jsonの詳細が知りたければ
[Feature flags](https://docs.aws.amazon.com/cdk/v2/guide/featureflags.html)||Contextに設定できる、v1からの破壊的な変更を元の挙動に戻すフラグ。initで設定される`"@aws-cdk/core:stackRelativeExports"`などの解説
Aspects||Stack内のリソースに一気にタグつけ
Escape hatches||CloudFormationではできるけどCDKではまだ出来ないってときに。CloudFormationで何ができるかは[「AWS resource and property types reference」](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html)を参照
Bootstrapping||「重要な概念」でブートストラップは説明済。v1とv2は別のものを使うとか、v1のデフォルトで課金対象となっていた[CMK](https://docs.aws.amazon.com/ja_jp/kms/latest/developerguide/concepts.html)をv2ではデフォルトから外したとかv2でs3以外も選べるとか

## Best practices 
[ベストプラクティス](https://docs.aws.amazon.com/cdk/v2/guide/best-practices.html)。以下に概要を抜粋。意図は省略するため、元記事を読んだほうが良い。

カテゴリ|概要
--|--
組織|CDKを採用する際に、会社の他のメンバーのトレーニングと指導を担当する専門家のチーム(1人~規模により様々)を配置すること
コーディング|シンプルに始めて、必要なときにだけ複雑さを追加。[アーキテクチャのベストプラクティス](https://aws.amazon.com/jp/architecture/well-architected/?wa-lens-whitepapers.sort-by=item.additionalFields.sortDate&wa-lens-whitepapers.sort-order=desc)に従う。複数のアプリケーションを同じリポジトリに配置することは可能だが非推奨。インフラストラクチャとランタイムコードは同じパッケージを推奨。
コンストラクト|Stackではなく、Constructを使用してアプリをモデル化する。環境変数の参照はAWS CDKアプリのトップレベルに制限する。リソースの論理IDは変更しない。
アプリケーション|synthタイミングのロジックは使わない(ex. bad: CloudFormationが提供する`Fn::If` / good: CDKのコード上でif)。物理名ではなく、生成されたリソース名を使用する。削除ポリシーとログ保持を定義する。cdk.context.jsonで冪等性を担保する。AWSCDKにロールとセキュリティグループを管理させる(grantHogeメソッドの利用)

### スタック分割のベストプラクティス

* 通常、できるだけ多くのリソースを同じスタックに保持する方が簡単なので、それらを一緒に保持する。
  * ※ 分離する必要があることがわかっている場合は除く
* ステートフルリソース（データベースなど）をステートレスリソースとは別のスタックに保持する。
  * ステートフルスタックでターミネーション保護をオンにできるため
     * → データ損失のリスクなく、ステートレススタックを自由に作成・破棄。
  * ステートフルリソースは、コンストラクトの名前変更に対し、慎重にする必要があるため
     * 名前を変更すると、リソースが置き換えられるので、移動や名前変更がされる可能性のあるコンストラクト内にネストしてはいけない
         * （キャッシュのように、失われた場合に状態を再構築できる場合を除く）

## API reference
[APIリファレンス](https://docs.aws.amazon.com/cdk/v2/guide/reference.html)。バージョニングや互換性について。
[AWS CDK 2 AWS CDK Reference Documentation ](https://docs.aws.amazon.com/cdk/api/v2/)は今後、必要になったら読みに行く場所になりそう。

## How tos
[ハウツー](https://docs.aws.amazon.com/cdk/v2/guide/how_tos.html)。AWS CDKの短いコードサンプル。
困ったときにお世話になりそう。

項目|概要
--|--
環境変数から値を取得する|`process.env`
AWSCloudFormationのパラメーターを使用する|[コンセプト - パラメータ](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html)を参照
既存のAWSCloudFormationテンプレートをインポート|`CfnInclude`のL1コンストラクト型が利用できる
AWSCloudFormationパブリックレジストリのリソースを使用|CloudFormationコンソールやcliからの設定方法
SystemsManagerパラメータストアから値を取得|`StringParameter.ValueForStringParameter`でトークンを取得
AWS SecretsManagerから値を取得|`Secret.FromSecretAttributes`を利用
複数のスタックを持つアプリを作成する|2つのリージョンへのデプロイ例
CloudWatchアラームを設定|Queueでメトリックを作ってアラームを設定する例
コンテキスト変数から値を取得|cdk.jsonに書くか`-c hoge=fuga`のようにコマンドラインオプションで渡す
CDKパイプラインを使用したCI/CD|パイプラインスタックとアプリケーションスタックを定義。デプロイ後の検証など

## AWS CDK Toolkit（cdkコマンド）
[ツールキットコマンド](https://docs.aws.amazon.com/cdk/v2/guide/cli.html)など。オプションについても書いてあるので、使い始めは参照することが多くなるかも。

## CDKとAWS SAM CLI の統合(プレビュー版)
[AWSクラウド開発キット（CDK）（プレビュー）](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-cdk.html)

`sam-beta-cdk local invoke`でlambdaのローカルinvokeができたりする。
v1のときに[sam-beta-cdkのlambdaのローカル実行をWindows10+Vagrant+VirtualBox+Ubuntuで試してみたメモ](https://qiita.com/hibohiboo/items/942cd4192523d82faf0f)で試したことがあるが、時間が経っているから変わっている部分があるかも。
[使ってみた](https://qiita.com/hibohiboo/items/4d1c62ea98ecf0798064)。Feature Flagsを一つfalseにしないと動かなかった。


## Testing constructs
[Constructのテスト](https://docs.aws.amazon.com/cdk/v2/guide/testing.html)
`aws-cdk-lib/assertions`を使ったテスト手順。
スナップショットテストはv1からのマイグレーションで便利そう。
日本語だと[CDKv2で@aws-cdk/assertionsを試してみる](https://qiita.com/lune_sta/items/0e5a59855d3a668a4aa0)の記事とかよいかも。

## Troubleshooting
[AWSCDKの一般的な問題のトラブルシューティング](https://docs.aws.amazon.com/cdk/v2/guide/troubleshooting.html).
エラーメッセージでぐぐるとこのページに飛ばされそう。

## 2022.11.06追記 cdk.jsonのcontextについて

cdkのバージョンが上がるにつれ、冪等性を保つための項目がどんどん増えている。
以下は`cdk init --language typescript`したときに作成されるデフォルトファイルの、v20とv50の間での差分

```diff:cdk.json
{
  "app": "npx ts-node --prefer-ts-exts bin/cdk.ts",
  "watch": {
    "include": [
      "**"
    ],
    "exclude": [
      "README.md",
      "cdk*.json",
      "**/*.d.ts",
      "**/*.js",
      "tsconfig.json",
      "package*.json",
      "yarn.lock",
      "node_modules",
      "test"
    ]
  },
  "context": {
    "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
    "@aws-cdk/core:stackRelativeExports": true,
    "@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
    "@aws-cdk/aws-lambda:recognizeVersionProps": true,
+    "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
    "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
    "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
    "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
+    "@aws-cdk/core:checkSecretUsage": true,
+    "@aws-cdk/aws-iam:minimizePolicies": true,
+    "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
+    "@aws-cdk/core:validateSnapshotRemovalPolicy": true,
+    "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
+    "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
+    "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
+    "@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
+    "@aws-cdk/core:enablePartitionLiterals": true,
    "@aws-cdk/core:target-partitions": [
      "aws",
      "aws-cn"
    ]
  }
}

```

### CDK V2で追加された機能
[Feature flags](https://docs.aws.amazon.com/cdk/v2/guide/featureflags.html)より

プロパティ|意味
--|--
"@aws-cdk/aws-lambda:recognizeLayerVersion"|Lambda 関数に関連付けられたレイヤーを更新すると、新しいバージョンの関数が作成されることを確認する
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver"|デフォルトで、サービス拡張コンテナへのログインを有効にする
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName"|[InstanceRequireImdsv2Aspect](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.InstanceRequireImdsv2Aspect.html)で作られた名前が一意であることを確認する
"@aws-cdk/core:checkSecretUsage"|安全な場所でのみ Secrets Manager の値を使用できる
"@aws-cdk/aws-iam:minimizePolicies"|可能であれば、IAM ポリシーの作成を最小限に抑える
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName"|Amazon EC2 または Fargate クラスターをインポートするときに、新しい ARN 形式を使用する
"@aws-cdk/core:validateSnapshotRemovalPolicy"|`SNAPSHOT`に`Removal Policy`が提供されていないリソースを指定したときに`cdk synth`が失敗するようにする[*](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-attribute-deletionpolicy.html)
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName"|`cross-account key alias`がパイプライン内で一意であることを確認する
"@aws-cdk/aws-s3:createDefaultLoggingPolicy"|デプロイ時にバケット ポリシーを自動的に作成するサービスで S3 バケットを使用する場合は、AWS CDK で必要なポリシーを構成する
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption"|Amazon SNS トピックにサブスクライブされた Amazon SQS キューで、Amazon SNS 全体ではなくトピックのみに復号化のアクセス許可を制限する


### CDK V1とV2でデフォルトの設定が異なる部分
falseに設定するとv1の挙動に戻すことができる。

プロパティ|フラグを設定するタイミング
--|--
"@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId"|アプリケーションが複数の Amazon API Gateway API キーを使用し、それらを使用プランに関連付ける場合
"@aws-cdk/core:stackRelativeExports"|アプリケーションが複数のスタックを使用し、あるスタックから別のスタックのリソースを参照する場合。れにより、AWS CloudFormation エクスポートの構築に絶対パスと相対パスのどちらが使用されるかが決まる
"@aws-cdk/aws-rds:lowercaseDbIdentifier"|アプリケーションが Amazon RDS データベース インスタンスまたはデータベース クラスターを使用し、これらの識別子を明示的に指定する場合
"@aws-cdk/aws-lambda:recognizeVersionProps"|falseにした時の挙動 -> Lambda関数の変更を検知した場合にmetadataをCDKは含めるようになる。metadataの変更のみの場合に、`duplicate versions are not allowed`のエラーでデプロイに失敗する。
"@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021"|アプリケーションが Amazon CloudFront ディストリビューションで TLS_V1_2_2019 セキュリティ ポリシーを使用している場合
"@aws-cdk/aws-apigateway:disableCloudWatchRole"|
"@aws-cdk/core:enablePartitionLiterals"|


### CDKでの設定法
`setContext`メソッドで設定可能。
[cdk v2 guide context](https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/context.html)
[AWS CDKでcdk.jsonのコンテキスト(context)を使用する方法](https://confrage.jp/aws-cdk%E3%81%A7cdk-json%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88context%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/)

```ts
const app = new cdk.App()
app.node.setContext('@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId', false)
```


## 参考

[AWS Cloud Development Kit (AWS CDK) v2 is now generally available](https://aws.amazon.com/jp/about-aws/whats-new/2021/12/aws-cloud-development-kit-cdk-generally-available/)
[AWS CloudFormationを介して機能を利用できるかどうかを判断](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html)