はじめに
業務で Terraform を使うことになりました。
これまで IaC といえば AWS CDK しか触ったことがなく、IaC そのものも初心者です。
「Terraform では何ができるのか?」「CDK とどう違うのか?」── 実際に手を動かす前に、まずは思想や仕組みを整理しておきたいと思い、調べた内容をまとめました。
※ CDK vs Terraform はよく宗教論争になりますが、私はどちらも初心者、かつ、あくまで私個人の抱いた感想です。
※ 理解を深めるためにまとめた記事です。Terraform に詳しい方からの「ここ違うよ」「こう考えるといいよ」などのコメントも歓迎いたします!
Terraform とは
Terraform は IaC(Infrastructure as Code)を実現するためのツールのひとつです。
AWS で言えば VPC、EC2、RDS、Lambda などなど、リソースをコードで定義し、CLI で実行することで作成・更新・削除ができます。
つまり、CloudFormation (CDK 含む)でできることは、基本的に Terraform でも可能です。
ただし CloudFormation は AWS 専用ですが、Terraform はマルチクラウド対応な汎用的なツールです。
一度学習してしまえば、AWS、Azure、GCP、さくらなどで共通して使うことができます。
宣言的(こうなってほしい)な記述方法を取り、HashiCorp Configuration Language (HCL) という独自の言語を使用します。
どんな仕組みで動いている?
Terraform は、各種クラウドサービスが提供する Provider と呼ばれる API のラッパーとして機能します。また、状態 (state) を記録しておき「理想(コード)と現実(状態)の差分を解消する」ように機能するのが特徴です。
状態 (state) とは?
Terraformが 「自分が何を作ったか」 を覚えているためのファイルです。
Terraform は、通常 plan
時に実リソースの状態を取得して state を更新し、更新後の state と HCL を比較して差分を出してくれます(-refresh=false
オプションで実リソースを見ないよう挙動変更することも可能)。
人間の手で AWS コンソールから設定などを変えてしまった場合、実リソースが state と一致しないこととなりますが(これを drift と呼びます)、これも検知できます。
ただし、どれが正しいか決めるのは人間です。「なんで実リソースと state で違う!?」 犯人探しが始まります。
※ この「状態」の管理は、Terraform に限った話ではなく、CloudFormation においても AWS が内部で管理してくれています。Terraform では、自前管理する必要があるというだけです。
状態が信じられないものになるとき
「ちょっとコンソールでいじって試してみましたが、state こそが真実です」これが確認できているのであれば、drift が起きてもすぐに大きな問題にはなりません。
状態が信じられないのは以下のような場合です:
- チームで state を共有していないと「誰が何を作った?」が不明に
- drift 多発により
plan
が信用できない - 運用しきれない状態で CI から
auto-approve
(yes
省略で突き進む)だけ回し続けている
→ でも逆に、ちゃんと state 管理できるなら、コードに全責任を持てるインフラ運用が可能
Terraform の汎用性とは?
書く内容が違うのに、どこが汎用?? provider の指定や、リソースの指定など、クラウドプロバイダーごとに記載内容はまったく違います。
たとえば、AWS 用に書いた S3 作成コードで、Azure の Blob Storage を作ることはできません(当たり前)。
では、汎用的だと何が嬉しいのでしょう? 学習コストが抑えられるだけ?
Terraform の汎用性が真価を発揮するのは、マルチクラウド環境だと思っています。たとえば Datadog / Cloudflare / Auth0 / GitHub までまとめて IaC したいといったとき、「内容」は違っても、「管理の仕組み」が共通である意義は大きいです。
Terraform で扱うことで:
- provider 切り替えだけで、同じルールで管理できる
-
plan
/apply
/destroy
のフローが全部共通 - state ファイルに全部まとまる(Cloudflare の DNS も、AWS の ALB も、GitHub のリポジトリも。クラウドとSaaSを横断して「ひとつのIaC」として扱える)
- 変数とモジュールの思想を共通にできる
CDK との比較を少しだけ
宣言的な Terraform vs 手続き的な CDK
CDK(とくに TypeScript などの命令型言語で書く場合)は、「書いた順に実行される」 ため、リソース間の依存関係を意識して記述する必要があります。
「何を先に用意するか」「どのタイミングで参照するか」が実行時の挙動に直結します。
Terraform のように「順不同で書いても依存関係を自動で解決してくれる」ような挙動は CDK にはありません(依存のあるリソースが未定義のまま参照されると、実行時にエラーになります)。
ただし、Terraform も CDK も「IaCであること」に変わりはなく、どちらを選ぶかは チームの事情や思想の好み に依存する部分が大きいと感じました。
細かく見ていけば他にもいろいろと違いはあると思いますが、このあたりは長く続く宗教論争なので、初心者の私はこれ以上は踏み込みません。
師匠に本記事をレビューいただいたところ 「CDK だって、できる限り宣言的に書くべき」 とアドバイスをもらいました。
確かに、CDK を命令型に書こうと思えばいくらでもそう書けてしまいますが、副作用を伴うような処理(たとえば Docker イメージのビルドなど)はなるべく Construct に閉じ込めて、リソース定義自体は宣言的なスタイルを保つべき、とのこと。
道具の思想も大切ですが、結局のところは「使い手の設計力にかかっている」という示唆を食らって、「うっ、耳が痛い…」となりました。
アーキテクトが AWS で完結しているときは?
ここまで調べてみて、AWS 内で完結しているという条件のもとでは、正直、以下のような理由で CDK (CloudFormation ) のほうが扱いやすそうと感じました。
- CDKの抽象化(高レベル Construct)
- CDK では、AWS がよくある構成パターンを「高レベル Construct」として用意してくれているため、詳しい設定を書かなくても、ベストプラクティスに近い形でリソースを立ち上げやすい。(逆に言うと細かい設定はおまかせ)
- Terraform で同じことをやるには、モジュールや定義を自分たちで組み立てる必要がある。
- CloudFormation の state 管理を AWS に任せられる安心感
- アプリケーションコードとインフラが同じ言語で書ける気持ちよさ(TypeScript ならTypeScript だけで完結する)
補足:CDK for Terraform(cdktf)という選択肢もあります。
TypeScript や Python で Terraform リソースを書くことができますが、実態は Terraform の世界観に沿ったコードを別言語で書けるだけなので、Terraform 的な知識(state、provider、backend、lifecycle など)を持っていないと、扱いは難しいように感じました。
また、AWS CDK のような「高レベル Construct で便利に抽象化してくれる」要素が現時点では少なく、単純に CDK の出力を CloudFormation → Terraform に変える、という感覚で使えるものではなさそうです。
Terraform の運用はルールが重要
また、Terraform の柔軟さは裏を返せば「人間がルールを守らないと危険」という側面も持ちます。
-
state
ファイルの破損や競合 - チームメンバーが勝手に
apply
して壊す -
auto-approve
付きで CI 回すと暴走
→ 対策には、state backend のロック機能(S3 + DynamoDB)や GitOps 的な運用ルールの徹底が不可欠です。
また、リソース名にグローバルな一意性が必要な場合(S3バケットなど)は、変数設計や命名規則も工夫する必要があります。
おわりに
Terraform を改めて調べてみて、「コードに責任を持たせる」思想や、「状態と理想を突き合わせる」設計の深さに少しだけ触れられた気がします。 今後は Terraform に加えて、構成管理ツールである Ansible も合わせて学んでいきたいと思っています。 Terraform で土台を作り、Ansible で中身を整えるという分担を体感しながら、少しずつ IaC の感覚を身につけていけたらと思っています。