CDK初心者が開発で遭遇したトラブルと解決法

CDK初心者が開発で遭遇したトラブルと、その解決策をまとめました。
同じトラブルで苦戦しないよう、ぜひ参考にしてください。

## 目次
<b>プログラミング関連のトラブル</b>
・プログラミング力不足
・クラス作成の思想のずれ
・配列利用によるトラブル
・構造化の失敗による設定箇所の分散
・設定値の外だしは.tsファイルで
・どこまで設定値を外だしするか
・リファクタ時にConstructにまとめると論理IDが変化する
<b>デプロイに関するトラブル</b>
・同名リソース作成によるデプロイエラー
・db作成に時間がかかる
・スタック間参照削除時トラブル
・循環参照トラブル
・リソース作成順序エラー
・スタックに作成可能なリソース数の上限
・VPCLambdaの削除
<b> 実装が難しかった内容 </b>
・Ｓ３クロスリージョンレプリケーション
・Aurora作成時等に自動作成されるロググループの設定変更



## プログラミング関連のトラブル

### プログラミング力不足
CDKはプログラミングです。プログラミング経験の少ない基盤メンバーだけでチームを組むと、コード執筆やデバッグで苦戦します。個人的には、アプリ開発経験者がAWSの知識を身に着けるより、基盤メンバーがゼロからプログラミングを習得するほうが難しいと感じました。アプリ経験をアサインしましょう。

https://qiita.com/Figure_Skate_IT/items/761e626b4213b6321e6d

https://qiita.com/Figure_Skate_IT/items/83a395d26567f01b3ae2

### クラス作成の思想のずれ
最初にクラス設計を行わないと、個々の開発メンバーが勝手にクラスを作成し、コードがバラバラになります。また、独自のクラスを作成せず、全設定をべだ書きした場合、横展開で修正が必要な場合、大変時間がかかり、とても非効率です。クラスや関数の使い方には様々な方法があるので、メンバー間で認識をそろえることが重要です。

https://qiita.com/Figure_Skate_IT/items/0e70f2d6b10cede6c0db

### 配列利用によるトラブル
セキュリティグループ等、ループを回して大量にリソース作成する際、配列に格納してはいけません。要件変更や設計ミスなどでリソースが削除された際、参照の際の配列番号がずれて修正が大変になりました。辞書に格納するとKeyで参照でき、分かりやすいためおすすめです。


### 構造化の失敗による設定箇所の分散
スタックやコンストラクトの構造化に失敗すると、複数のスタック・コンストラクトでS3やCloudWatchLogs等が登場します。横展開で修正が必要になった場合、どこで設定がされているか分からず迷子になります。Configファイルに設定値を外だしする場合も、同じ設定が複数個所で繰り返されないよう注意が必要です。環境差分を定義するファイルと環境共通の値を定義するファイルを分け、上手く構造化してください。


### 設定値の外だしは.tsファイルで
環境差分の設定値などをConfigファイルに外だしする際、jsonファイルではなく.tsファイルを利用しましょう。Jsonファイルにはコメントが書けないため、何の設定か分からなくなることがあります。また、jsonファイルではactions.OpsItemSeverity.CRITICAL等、CDKで型が定義されている設定値を表現できません。TSファイルにオブジェクト型で記載する方式にすると、コメントや型宣言を利用できるため便利です。

### どこまで設定値を外だしするか　
環境差分の設定値などをConfigファイルに外だしする際、どこまで外だしするか認識をそろえましょう。①環境差分のみ外だしする②将来環境別に変えたい設定値も外だしする③リソース名を外出ししてスタック間参照を避ける④定数はすべて外出しして、CDKではロジックの未実装する等、人によって意見が分かれることがあります。

### リファクタ時のトラブル
リファクタ時にべた書きしていたリソースをConstructを継承したクラスの中にまとめると、論理IDが変化してリソースの再作成が発生します。特に、リソース名を明示的に指定している場合、同名リソース存在による再作成の失敗でデプロイエラーが起きることもあります。再作成防止には、元の論理IDが変化しないよう、Constructを利用しないクラスや関数を利用するなどの工夫が必要です。ただ、コードのまとまりが悪くなる可能性もあるので、影響を調査したうえでリソースの再作成を許容する選択もありです。


## デプロイに関するトラブル

### 同名リソース作成によるデプロイエラー
CDKでは同じ名前のリソースを作成しようとするとデプロイエラーになります。このため、CDKが自動生成するリソース名の使用が推奨されています。しかし、自動生成されるリソース名が分かりにくいという意見もあります。リソース名を指定する場合、命名規則の末尾にデプロイ日などの識別子を入れて、同名リソース作成によるエラーが起きないようにしましょう。


### db作成に時間がかかる
rdsの再作成を伴うデプロイを行う場合、１回のデプロイに１時間かかることはざらです。なかなかエラーが解決せずトライ＆エラーをすると、気づけば深夜になることもあります。dbのデプロイ前は有識者がチェックし、なるべくエラーを減らしましょう。


### スタック間参照削除時トラブル
CDKのスタック間参照で、参照先リソースで参照を削除する場合、デプロイエラーが発生します。解決方法は４つあります。
①参照先スタックを cdk deploy -e "スタック名"　でデプロイした後、 cdk deploy --all で参照元スタックをデプロイする。
② 参照元で exportValue を用いる
③ SSMパラメータに名前を格納し、参照自体行わない。
④ (リソース名を明示的に指定する場合)リソース名をCofingファイルに格納し、Configファイルを参照することで、スタック間参照を行わない。

スタック間参照では以下の循環参照トラブルも発生するので、スタック間参照を利用しない構成がベストだと思います。

https://dev.classmethod.jp/articles/aws-cdk-closs-stack-reference-exportvalue/


### 循環参照トラブル
CDKのスタック間参照で、参照先リソースから参照リソースの設定値を変えると、循環参照となりデプロイエラーが発生します。例えば、CDKが自動で作成するLambda関数等にスタック間参照でSGを渡す際、自動でルールが書き換わり、循環参照エラーが発生します。スタック間参照させず、fromArn 系のメソッドで既存リソースを再作成して渡すことで解決できます。fromArn系のメソッドを使う場合、スタック間参照ではなくSSMパラメータ等に格納したArnでも動作するので、スタック間参照を利用しない構成がベストだと思います。

https://dev.classmethod.jp/articles/best-way-to-reference-parameters-in-cdk/



### リソース作成順序エラー
ロググループに属するログストリーム等を作成する際、The specified log group does not exist.　というリソース作成順序に伴うエラーが発生することがあります。addDependsOnやaddDependencyを使って明示的にコンストラクト同士の作成順序を指定すると、このエラーを回避できます。

https://tmokmss.hatenablog.com/entry/cdk_two_types_of_add_dependency

https://dev.classmethod.jp/articles/explicitly-define-dependencies-between-resources-in-aws-cdk-with-adddependson/

### VPCLambdaの削除
VPC内に作成したLambda関数を削除する際、以下トラブルが発生して１時間ぐらいDELETE_IN_PROGRESS状態で止まってしまいます。対策は以下記事に書かれています。

https://zenn.dev/fffukken/articles/86325ec0db0205

### スタックに作成可能なリソース数の上限
１スタックで作成可能なリソース上限は500です。SGを細かく分けたり、たくさん監視を行ったりすると、すぐにリソース上限に抵触します。スタック間参照トラブルを避けるため、できるだけスタック数を少なくすることが推奨されていますが、後からスタックを分割することは結構大変です。初めからリソース上限を考慮してスタック分割方針を決めましょう。また、スタック間のパラメータ受け渡しはConfigファイルやSSMパラメータのみとし、スタック間の直接的な参照を避ける構成にすると、スタックの分割も簡単になります。


## 実装が難しかった内容

###  Ｓ３クロスリージョンレプリケーション
S3クロスリージョンレプリケーションでは、レプリケーション元とレプリケーション先2つのリージョンのスタックの連携が必要です。スタック間参照はトラブルが多いため、SSMパラメータを持ちた方式がおすすめです。別リージョンのSSMパラメータを読み取るカスタムリソースの作り方が以下記事に記載されていて、そのまま利用できます。以下方法はS3だけでなくその他のクロスリージョンレプリケーションにも応用可能です。

https://zenn.dev/takeyuwebinc/articles/53fceeb3cd80ca



### Aurora作成時等に自動作成されるロググループの設定変更
DynamoDB等のログ監視実装時は、自分で作成したロググループを指定できます。しかし、Aurora作成時、RDSOSメトリクスやPostgreSQL等のロググループは自動で作成され、好きなロググループを指定することはできません。Aurora作成時に自動作成されるロググループと同名のロググループを事前に作成することで、暗号化や保持期間、S3へのレプリケーションなどをCDKで設定できます。※Auroraデプロイ後に設定変更したい場合、自動作成されたロググループを削除してからAuroraを再デプロイする必要があるため、結構大変です。



## まとめ
・CDK開発ではプログラミングスキルが求められるため、アプリ開発経験者をアサインしましょう。
・スタック間参照を使うと様々なトラブルが発生する。SSMパラメータを利用し、スタック間参照を避けましょう。
・スタック内のリソース数上限などの制約を事前に把握したうえで、上手く構造化し、プログラミングのメリットを最大限活用しましょう。
・先人の知見を有効活用し、同じトラブルで悩まないようにしましょう。