🏭

Terraform信者からみたAWS CDKの好きなところとか

2023/12/10に公開

はじめに

男は深い苦悩に囚われていた。彼はインフラ構築のたびに生まれる環境の多様性に悩まされていた。

男はインフラをコードで形成し一貫性を保つ可能性を持つ「Terraform」という存在に出会った。この新しいツールは、環境の構築を手続き的なスクリプトから解放し、コードによる宣言的なアプローチを提供していた。そしていつしか、男は「Terraform」の魅力に取り憑かれていた。

しかし新たな職場で、男は新たな可能性を秘めた「AWS CDK」という存在に出会った。これは、インフラストラクチャをコードで構築するためのフレームワークであり、従来のインフラの制御や管理に加え、AWSの機能を直感的に扱える特長を持っていた。

男は戸惑いつつも、「AWS CDK」が提供する柔軟性と拡張性に魅了された。新たな手法に対する好奇心が彼を駆り立て、新しい道を模索する決意を固めたのである。
-- edited by ChatGPT

要約:
これまでTerraformを好んで使っていましたが、仕事で初めてAWS CDKを使うことになったので今の所感を書き記します。

なぜ Terraform が好きなのか

  • インフラ構築時にWebコンソールを何度もポチポチして作る手間から解放される
  • 宣言的な記述がわかりやすく、処理を追いかける必要もなく、冪等性が担保しやすい
  • 圧倒的に巨大なコミュニティを有し、linterやCI/CDのためのツールなど便利なエコシステムが豊富

AWSをメインに管理している場合CloudFormationでも同様のことが実現できますが、いくつかの点でTerraformの方が使いやすいと感じています。

  • コマンドがシンプルで使いやすい
  • YAMLの表現能力では限界を感じる
  • Azure, GCP, NewRelic, Github etc. 同様の記述で管理できる

AWS CDK とは

メジャーなプログラミング言語によってインフラを定義しプロビジョニングするためのフレームワークです。記述されたコードからCloudFormationのテンプレートファイルを生成し、各リソースのデプロイ・更新はCloudFormationの機能を利用します。


(AWS CDK とは - AWS Cloud Development Kit (AWS CDK) v2 https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/home.html)

AWS CDKに含まれるライブラリはL1/L2/L3の3つのレベルのコンストラクトに分類されます。
L1はCloudFormationの表現がそのまま引き継がれる形で提供され、L2はデフォルト値や便利なメソッドが追加された形、L3は複数のリソースの組み合わせたパターンで提供されます。

GitHubにてソースコードが公開されていて誰でもコントリビュートできます。
また、AWS Supportのサポートケースから問い合わせることも可能です。

Terrafrom との違い

CloudFromationがTerraformと並ぶ宣言的なテンプレート管理の仕組みで、AWS CDKはそのテンプレートを生成するツールです。そもそもの位置付けがTerraformとは異なりますが、インフラをコード管理するツールという括りで比較します。

AWS CDKの好きなところ

型システムによる制約

Terraformではリソースの設定項目に指定する値の型はstring/number/bool//list/set/mapのいずれかに限定されます。これらは汎用的すぎるために静的解析が難しいです。
例えば、他のリソースに依存する場合に依存先はIDをstring形式で示しますが、ECSのクラスターIDが必要な箇所にRDSのインスタンスタイプが入力されていても文法エラーにはなりません。id, name, arnなど似たような属性がある場合に何を選択すべきか悩まされることもあります。

AWS CDKではリソースごとにクラスが定義されています。
前述の他のリソースとの依存を示す際にはインターフェースを通してオブジェクトを渡す形になります。
IDEのサポートがあればコードを書いている最中から解析されるため、AWSに不慣れな初学者でも迷いなく適切に関連付けられます。

terraform
resource "aws_ecs_service" "example" {
  name            = "example"
  cluster         = aws_ecs_cluster.example.id           #string
  task_definition = aws_ecs_task_definition.example.arn  #string
}
cdk
declare const cluster: ecs.Cluster;
declare const taskDefinition: ecs.TaskDefinition;

const service = new ecs.FargateService(this, 'Service', {
  cluster,
  taskDefinition,
});

IAMポリシー, SecurityGroupルールの暗黙的な設定

L2, L3コンストラクトを使うことで、リソース間で連携するために必要なIAM Roleに紐づくポリシーやSecurityGroupのルールの設定など開発者が意識しなくても補完されます。

例えば、ECSサービスの作成時にenableExecuteCommandを有効にすると、タスクロールに'ssmmessages:CreateControlChannel', 'ssmmessages:CreateDataChannel', 'ssmmessages:OpenControlChannel', 'ssmmessages:OpenDataChannel'のアクリョンを許可するポリシーがアタッチされます。他にもログを利用する際のCloudWatch Logsへのアクションなど、特定のユースケースを満たすために必要な複数の設定をライブラリがまとめて設定してくれます。しかもAWSが公式にサポートするためベストプラクティスに沿った最小構成が期待できます。
IAMやSecurityGroupの変更内容はデプロイ前に確認できるため、全くの想定外になる心配も少ないです。

許可すべきアクションは、自身で実装しAPIを叩くのならいざ知らず、AWSの内部実装に関わる部分はドキュメントを参照してコピペする他ないため、ツールとしてサポートしてくれるのはありがたいです。

Terraform の方が好きなところ

宣言的な記述

AWS CDKでは汎用的なプログラミング言語を利用するため、宣言的に記述するTerraform, CloudFromationとは違い、実行順序を気にかけてコードを記述する必要があります。「構成図の上から順に書く」みたいな自由はなく、依存する順に処理されるように気にかけなければならないのは、Terraformに慣れた身には違和感があります。
表現の自由度も高いため、管理するリソースが増えてきた時には、冪等性や可読性を保つために多少開発者の側で注意する必要があるかもしれません。

diffの挙動

terraform planで出力される差分がコードと実体の差分であるのに対し、cdk diffの出力はコードから生成されるテンプレートとCloudFormation上のテンプレートの差分です。
実体との差分はCloudFormationのドリフト検出により得られますが、この場合の差分はCloudFormation上のテンプレートと実体の差分です。
ローカルコードによる変更を確認するにはdeploy --no-executeにより変更セットを作成し変更内容を確かめます。

ローカルコードを書き上げる際に、事前に発生していた意図しない差分の修正が必要な時など、Terraformであれば通常のデプロイオペレーションの中で使うコマンドの結果だけ見ればどこに差分があるか、どう直せばいいかまで一目瞭然であるのに対し、AWS CDKでの差分修正は少し手間に感じます。 (これはAWS CDK自体ではなくCloudFormationとTerraformの差といえるかもしれません)

特に既存のリソースのインポートをする際にはL2コンストラクトでは設定できない差分が含まれていることも多く、修正方法も泥臭くなりがちです。
ゴリゴリにカスタマイズされている場合、L1コンストラクトのみで書く手段もありますが、L1コンストラクトで書くならTerraform (HCL) で記述してもほとんど変わらずAWS CDKの旨みがかなり薄くなる印象です。

このあたりは、新規構築時からAWS CDKによって管理し、コード以外からの変更を避けることでほとんど問題にはなりません。とはいえ、学習も兼ねてひとまずコンソールから作ってみたり、インシデントやメンテナンスで急ぎコンソールやCLIで変更を加えたりしたい場面はあるでしょう。ぐちゃぐちゃになる前に気づいて細かく修正できるフローを別途用意しておきたいところです。

場面に応じてどちらも使えると良さそう

AWSにロックインした環境であればAWS CDKはかなり便利に使えそうです。
特に、とにかくスタートダッシュを決めたい新規構築時や、インフラを専任チームだけで管理せずアプリケーション開発チームがオーナーシップを持ってメンテナンスする場合には、AWSに不慣れな初学者でも安全に効率よくインフラを操作するのに活躍すると感じています。

一方で、aws_ssoやaws_identitystoreのようなL1コンストラクトでしか記述できない (L2を作る必要性も薄い) リソースはTerraformで書いても大差ないとも感じます。むしろTerraformに寄せておくことでDatadogなど他サービスのアカウントもまとめて一括で管理ができて運用しやすいように思います。

なお、Terraformにも汎用プログラミング言語を利用したCDK for Terraform (CDKTF) が存在します。記述方法・内容自体は AWS CDKとほとんど同じです。CDKTFとAWS CDKを合わせて利用することで、サービスによってバックグラウンドがTerraformであってもCloudFormationであってもその差異をあまり感じないようにできそうです。

AWS CDKもCDKTFもまだまだ発展中です。実際に触りながら、使い方を検討していきたいと思います。

Discussion