AWS CDKとTerraformどちらを使うのが良いのか？

# 今日のお題
> 結局、CDKとTerraformどっちがいいんだろう、という宗教論争

それぞれをある程度触ってきた上での個人的見解を今後の自分のためにまとめます。
長くダラダラした記事なると思いますがご容赦を。

# 先に結論
CDK、非常にいいんだけれど、ちょっと辛いかも。
ずっと運用することを考えるとTerraformかな。
(2022/07/22追記)
・・・と思っていたが、使い方によってはCDKの方が良さそうという人になってきました。
その内容は　[こちら](https://qiita.com/luton-mr/items/afe70781807bf3b5016a#20220722%E8%BF%BD%E8%A8%98cdk%E3%81%AE%E6%96%B9%E3%81%8C%E8%89%AF%E3%81%84%E3%81%A8%E6%80%9D%E3%81%86%E3%82%88%E3%81%86%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E7%90%86%E7%94%B1)

# そもそも、CDKとかTerraformってなんだ？
一言で言えば、Infrastructure as Code(IaC)のツールです。
AWSに限らず、GCPやAzureなど様々なクラウドサービスがありますが、これらのクラウドサービス上でコードによりインフラ管理を行う仕組みがIaCです。

これにより、コードさえあれば、どのアカウントにも同じインフラをライトに構築することが可能となります。
もちろん、構築だけでなく削除も。

このツールを選択する際に、これまた様々な選択肢があります。
AWSユーザに一般的なものとしては、

* AWS CLI
* Cloud Formation
* AWS CDK(Cloud Development Kit)
* Terraform
* Ansible

あたりでしょうか。

AWS CDKは、PythonやTypeScriptなどのプログラミング言語によって、CloudFormationのテンプレートを生成できるため今激アツなIaCツールです。
Terraformは、AWSだけでなくGCPやAzureなど他クラウドサービスにも対応していることから、純正ではないIaCツールとしては主力のツールです。

そのため、今回はこの２つに絞ってメリデメを考えていこうと思います。

# CDKのメリット・デメリット
## メリット
### コード量が少なくて済む
CDK最大のメリットだと思います。
コード量が少なくて済む最も大きな要因は、バックエンドで自動的にAWSのベストプラクティスに沿った設計内容が反映されるからです。

例えば、VPCを一つ作り、その中にはパブリックサブネットとプライベートサブネットを2つずつ作りたい場合を考えます。
これを実現するには、VPCとサブネットの他に、IGWやNGW、ルートテーブルを作成する必要があります。
が、CDKで記載するとこんな感じ。

```py
from aws_cdk import core
from aws_cdk import (
    aws_ec2 as ec2
)

class VPCStack(core.Stack):

    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Parameter
        vpc_name = "sample-vpc"
        vpc_cidr_block = "192.168.0.0/16"

        self.create_vpc(vpc_cidr_block=vpc_cidr_block, vpc_name=vpc_name)

    # Create VPC
    def create_vpc(self, vpc_cidr_block, vpc_name):
        vpc_network = ec2.Vpc(self, vpc_name, cidr=vpc_cidr_block)
```

最後のたった1行だけの記述ですべてできちゃいます。
生成されるCloudFormationのテンプレートは、約400行でした。これだけで90%以上のコード量減です。
AWSでIaCなら初手はCloudFormationだろう！!という方がほとんどだと思いますがほぼほぼ全員が「これだけ書くならコンソールでポチポチやるほうが早い」と思ってIaCするのを辞めるんだと思っています。

### 条件分岐・繰り返しが使える
プログラミング言語を使えるので当然ですが、条件分岐や繰り返しを使うことでさらなるコードのスリム化が可能です。
(2022.07.22追記)
ただし、条件分岐を使うとコードの保守性が落ちる可能性が高いです。
例えば、特定のアプリ向けに複数のS3バケットを作ることを考えます（仮にバケットA、バケットB、バケットCとしましょう）
命名規則も同じ、オブジェクトのライフサイクルも同じだからfor文で一気に作っちゃおう！とコーディングしたが、後に要件が変わってバケットBのライフサイクルだけ他と変えなければいけないようなパターン。
コードにif文追加して「バケットBならライフサイクルをこうする」みたいなことしますか？可読性も落ちますよね。
なので条件分岐・繰り返しが使えることはメリットですが、利用価値があるかと言えば僕はそうでないと思いました。

### AWS公式のツールであること
AWS公式のツールであるため、有償のサポート契約を結んでいれば何か問題が発生した場合にはAWSのサポートが助けてくれます。
また、CloudFormationをラッパーしているため、CloudFormationで出来ることはCDKでもできます。

### アップデートがめちゃめちゃ早い
だいたい1週間に1回はアップデートされてるんじゃないかなぁ。
継続的に機能改善と機能追加が繰り返されており今注力されてるんだなというのが伝わってきます。

## デメリット
### コードが属人化していく
プログラミング言語を使えることによる影響と言えると思いますが、誰が書いてもだいたい同じコードになるかと言われるとそうではない。
それぞれの言語で、個人個人のコーディングの癖があると思いますので結果、そのコードは属人化します。
(2022.07.22)
ただし、条件分岐・繰り返しなどプログラミング言語特有の機能（仕組み、といったほうが良い？）を使わなければ、CloudFormationのテンプレートと同じようにだいたい誰が書いても同じようなコードになるはずですのでこのデメリットはカバーできるかと。

### レビューに知見が必要
上記により、レビューにはインフラの知見よりも、プログラミング言語の知見の方が重要になってきます。
インフラの知見はどちらかと言えば、設計書に基づいてコードが書けているかどうか？を見ればいいのでそこまで必要ないのかも。
ま、もちろんこのレビューに参加している時点でインフラの知見が無いとおかしいんですが。

### 細かいパラメータ調整ができない
ここは割と辛いところだと思います。
例えば、メリットであげたVPCの設定。
色々と考えずにたった1行で出来るのは素晴らしいのですが、例えばサブネットのネットワーク帯域を決めたいと思っても簡単には出来ません。
この場合、一度Cfnのクラスに変換して、CIDRを上書きする必要があったりします。正直面倒くさい。

### 結局何が出来上がるのかよくわからない
完全なメリットの裏返しですが、CDKでVPCを構築する例で書いたとおり、たった20行ほどで440行にのぼるCloudFormationのテンプレートが出来上がります。
この差分420行、もっと言えばVPCのCIDRとVPC名以外出来上がったものに関してコードの著者は理解しなくても良いということになります。

「とりあえず動くけれど、正直よく分かんないんだよね」

という人が量産されることになり非常に危険です。
アプリ開発に開発者が注力するため、という意図はとてもよく分かりますし大いに賛成なんですが、この状態ってほんとにいいのかなぁ…

### 既存リソースとの比較が出来ない
CDK辛いんじゃないかなぁと思った一番の理由です。
本来なら、IaCにした時点で、コンソールから手作業での変更は加えない！という覚悟と決心が必要なのがあるべき論です。

とはいえ十分に技術検証の時間を確保できなかったり、何故か突然目の前に納期がやってくることもあります。
どうにもならなくなってコンソールからちょこっと変えて動作確認してみるケースも発生するのがリアルな開発現場の実情です。

この時、基本的にはCDKは既存のCloudFormationテンプレートの状態と投入しようとしているテンプレートの差分を確認してdiffを表示してくれます。
コンソール上で作業した結果による変化は別途CloudFormationから操作しないと分からない。

そうなった場合には、CDKでもARNを指定することで既存リソースを取り込めますが…
ほんとにそんなことします？っていう。

### アップデートによる破壊的変更が度々ある
これもメリットの裏返しです。
バージョンアップに伴い、破壊的変更が結構な頻度で発生しています。しかも主力サービスで。
過去に実際体験した事例としては、RDSのDBエンジンの指定方法。
パラメータ自体が変わったので、CDKをアップデートした途端それまで通っていたコードが通らなくなります。

ちゃんとリリースノート見ろよって話ではありますし、バージョンアップするならその影響を考えた上で判断するのは当然ですが、それにしても破壊的変更の頻度が高すぎる。

### CloudFormationのログ、分かりにくい
これでも随分と改善された結果だと思いますが、CloudFormationのログはだいぶ癖があります。
パッと見ただけで分かるような直接的なエラーもあれば、何を言われてるのか、なんでだめなのかさっぱりわからないログもある。
そして、さっぱりわからないことが多いので、解決するまでに結構な時間を要します。

### 低スペックPCだと劇的に開発効率が落ちる
コーディングするのは別にテキストをただただ打ち込むだけなので低スペックPCでも全く問題ありません。
デプロイも、ネットワークさえある程度の品質があればあとはAWS内部で頑張ってくれます。
ただ、そのデプロイするために必要なCfnテンプレートへの変換にある程度のメモリが必要です。
会社で支給されている事務用PC（Windows10、8GB）だと全然ダメ。
バックエンドで動いているのはJavaScriptなのでヒープメモリサイズとの闘いも重要です。
ここを間違うと、CDKのためだけにメール確認すらできない状況になります。
（そもそもエンジニアに高性能な開発用PCは必須だろ、というツッコミは無しです）
このおかげで、大規模システムのコードを変換しようとすると`cdk deploy`を実行してから、デプロイ完了するまで平気で半日かかったりもします。

# Terraformのメリット・デメリット
## メリット
### 情報が豊富
コードを書くにあたり、最も大事なことだと思います。
IaCの主力ツールになっているTerraformですので、このQiitaにもたくさんの先人の皆さんが知恵を提供してくださっています。

### 既存リソースとの比較が出来る
これはCDKとは全く逆です。
だから、HashiCorpがCloudFormationラッパーにしなかったのでは？と思うところ。
`terraform plan`を実行した際に出てくる差分は、既存リソースとの比較結果です。

なので、たとえ手作業で変更した箇所がコードに反映出来ていなかったとしてもそこに気付けます。
うっかり、上書きして手作業の変更点が消えちゃった！しかも、その時のログが残ってないから元がどうだったのか分からない！みたいな嘘みたいなホントのよくある話も防止できます。

### デプロイまでの時間が早い
具体的な数値を書けないのが申し訳ないですが、これは体感の話です。
VPCとパブリックサブネットにEC2インスタンスを立てるだけの簡単なコードで試しただけでもデプロイ完了までの時間に差があったように感じます。
Terraformの方が圧倒的に早い。
体感的には、`cdk deploy`を実行して、デプロイ内容の確認が出力されるまでの時間でTerraformだとデプロイまで完了してしまうくらいの差です。
これは顕著に生産性に直結しますね。

### そこまでスペックは気にしなくて良い
僕個人で使っているのはMacbook Air(Intel Core i5)で、メモリも8GBと特に開発目的で購入したわけではないのでスペックは低いのですがTerraformはなんの問題もなく動作します。
ま、このMacで試したレベルのコードはCDKでも問題なく動作はするんですけどね。
過去、ある時期に会社でもTerraformでインフラ構築をしていた時期がありましたが、スペックが低いことによる悩みはなかったように記憶しています。

## デメリット
### AWS公式ではない
逆に言えば、ベンダ依存が無くなるとも言えるのですが、サードパーティ製のツールのためAWSのサポートは受けられなくなります。
これが、どこまでインパクトのあるデメリットかと言えば、そうでもないような気もします。

### よくわからないdiffとの闘いがある
見に覚えの無いdiffが発生することがよくあります。
新規デプロイ時には、例えばARNなどデプロイしないと確定しない（命名規則があるので予想はもちろんできますが）パラメータがあります。
既存リソースと比較をするため、2回目以降のデプロイでは

「Terraformのソース上ではデプロイ後でないと決まらない値のはずだが、既存リソースにはすでにパラメータが設定されている」

という状態が発生します。
そのため、見に覚えの無いdiffが結果として発生しますが、そのあたりは経験とカンで補えそうですね。

### 記述量の呪縛
CDKのメリットで記載したとおり、CloudFormationで440行記述しないといけないものがCDKだと20行です。
Terraformで実際設定する値はほぼCloudFormationのパラメータと同じなので、440行程度は書かないといけません。
正直、苦行ですし、システムの規模が大きくなればなるほど、そしてインフラエンジニアは慢性的に人手不足でしょうからそんな状態だともう苦行でしかありません。

ただし、これに関しては例えば自社で開発するシステムに関するアーキテクチャパターンを予め定義しておいてそれをモジュール化すればモジュール開発にだけ時間を割くことでその後の開発はこの苦行からは解き放たれます。

# まとめ
ほんとに一長一短だと思うんです。
なので宗教論争に発展するんだと思いますが、色々考えた結果、執筆時点での僕の考えはこうです。

* 使い所を考えて、どちらも使えばいいんじゃない？
* だけど、ずっと運用する環境にはやっぱりTerraformの方がいいと思う

です。では、それぞれのツールの使い所とは？

## CDK
### 使うべき人
* AWS初心者
* アプリケーションの開発に注力したい人
* さくっと技術検証がしたい人

こんなところではないでしょうか。
全てに共通して言えるのは、おそらくここに上げた3点に当てはまる方はそこまでインフラに明るくないのではないかなと思います。
そういう方が、AWSのベストプラクティスを踏まえてインフラを構築するにはどんな設定が必要なのか？を出来上がったものをベースに理解するためには素晴らしいツールだと思います。

さらに、コードの記述量は圧倒的に減るためとにかく本題のやりたいことに注力するためにはあらゆる壁を排除出来る可能性が高いためPoCなどのシチュエーションでは大活躍だと思います。

### やめた方がいいシチュエーション
* 手動でのインフラ変更が発生し得る開発
* 高スペックな開発PCを導入できない場合

実体験として、やめたほうがいいと思いました。

## Terraform
### 使うべき人
* インフラのことをある程度理解している人
* 細かなパラメータチューニングが必要なシステム

CDKでよしなにやってくれるリソースも含めて全てを自分で記述する必要があるため、当然のことながらインフラの知見は必須です。
これが無い場合には、苦行の連続だと思います。
ただし、それを補うための手段としてCDKで先にCloudFormationのテンプレートを作っておいて必要なリソースを明らかにした上でTerraformで実装するというような手もあると思いました。
もしかすると、その方がAWSのベストプラクティスを自然と導入しながら、自分たちが実現したい細かなパラメータチューニングが出来るので、より堅牢なシステムを構築できるかもしれませんね。

また、多くのシステムで運用中にパラメータを細かくチューニングするシチュエーションがあると思います。
そんなときには、確実にTerraformの方が柔軟に対応できます。

### やめた方がいいシチュエーション
* 開発者不足
* インフラの知見不足

物理的な記述量が多くなるので、分業出来なかったりお悩み解決を一緒にできるようなメンバーがいないようなシチュエーションでは開発スケジュール遅延に直結すると思います。
また、先にも書いたとおりインフラの知見が無いと思った通りの動作をするまでにたくさんの壁があるはずです。
例えば、

EC2インスタンスにIAMロールをアタッチするために、そのIAMロールとインスタンスプロファイルを関連付けないといけない

とか、コンソールでしか作業をしたことが無い人にとっては全く分からない（意識しない）話です。

# また、考え変わるかも？
どちらもまだプロフェッショナルだ！と言えるほど触ったわけではないですが、現時点での僕の見解をダラダラ書きました。
色々触っていくうちにまた考えが変わることもあるんでしょうが、用法用量を守って正しく使うことはどんなツールでも大事なことですね。

# (2022.07.22追記)CDKの方が良いと思うようになった理由
現在もCDKを使い続けいている私なりのベストプラクティスです。
たった一つ。「モジュール化しましょう」

AWSの構成自体にはベストプラクティスは存在するものの、コストとの兼ね合いで各社それぞれで思うベストな構成があると思うのです。
サービスの選定基準もそうだと思います。オンプレの経験値が豊富にあり、クラウドに移行したもののPaaSやSaaSのハードルが高ければEC2メインでアプリケーションは構成するでしょうし、Dockerが得意であればECSが選択肢に上がってくるでしょうしね。
そういった各社なりのよく使う構成をあらかじめモジュール化しておいて、CDK自体のモジュールは使わないようにすれば、ガバナンスも効かせられますし何より動くことが保証されるモジュールを使っているので変なトラブルを避けられます。

モジュール化を推進するチームが、予めドキュメントの整備やモジュールによって出来上がる構成図を整備しておくことで使いやすい環境もすぐに構築できます。
（そのチームを作るハードルがある・・・というのはおいておいて）
レビュアーもそのチームにお願いすることで、良し悪しは判断できそうです。

実際、私が所属する会社でよく使うアーキテクチャパターンをモジュール化することで、新サービスのインフラも爆速でデプロイすることができて、圧倒的生産性を確保できています。
ということで、この追記時点での考えは、CDKの方が良い、になりました。また変わるかもですけどね。