【テクニカル・上級編】Pulumi vs Terraform vs CDK for Terraform (CDKTF):どれを選ぶべき?徹底比較 – インフラ構成管理(IaC)活用バイブル

IaCのパラダイムシフト:Pulumi vs Terraform vs CDKTF ― 魂のアーキテクチャ比較と極限の最適化戦略

インフラストラクチャをコード化(IaC)する時代において、私たちは幾度ものパラダイムシフトを目撃してきた。
HCL(HashiCorp Configuration Language)という専用DSLの礼賛から始まり、汎用プログラミング言語による抽象化、そしてコンパイル型構成管理への回帰。

世間には「どれが初心者におすすめか」といった薄っぺらい比較記事が溢れているが、本書を手に取ったあなた、すなわち本番環境の極限の可用性を担保し、パイプラインの秒単位のレイテンシーに命を削るシニア・SREやインフラアーキテクトが求めているのは、そんな予定調和の比較ではないはずだ。

知りたいのは、「内部アーキテクチャのどこにボトルネックがあり、大規模環境でどう破綻し、どうすれば極限まで自動化とパフォーマンスを突き詰められるか」という、骨の髄まで踏み込んだ技術的真実だ。

本稿では、Pulumi、Terraform、そしてCDKTF(Cloud Development Kit for Terraform)の3者を、内部エンジン、状態管理、言語ランタイム、そして拡張性の観点から丸裸にする。

—

1. 内部アーキテクチャと実行モデルの深淵

まずは、これら3つのツールが「どのようにコードをインフラストラクチャに変換しているのか」という根本的なメカニズムを解剖する。

[ Terraform ]
HCL Code -> State Comparison -> Provider API -> Cloud API
(静的DSL + プロバイダーバイナリ)

[ CDKTF ]
TypeScript/Python -> Synth (HCL/JSON生成) -> Terraform Engine -> Provider API -> Cloud API
(2重の抽象化レイヤー)

[ Pulumi ]
TypeScript/Go/Python -> Language Runtime -> Pulumi Engine -> Resource Provider (gRPC) -> Cloud API
(真の汎用言語駆動 + gRPCアーキテクチャ)

Terraform:静的DSLとグラフ理論の極致

Terraformの本質は、有向非巡回グラフ(DAG)の評価エンジンである。HCLで記述された宣言的コードは、静的に解析され、依存関係グラフが構築される。

  • 通信プロトコル: コアとプロバイダー(AWS, GCP等)の間は、専用のRPC(gRPCベース)でプロセス間通信を行う。
  • メモリ・パフォーマンス: 大規模なステート(数万リソース)を扱う場合、Go製エンジンのメモリ消費量が急増する。特に `terraform plan` 時の依存関係解決と差分計算において、シングルスレッド性能がボトルネックになりやすい。

CDKTF:HCLへの「トランスパイラ」というジレンマ

CDKTFは、TypeScriptやPythonなどの汎用言語で書かれたコードを、一度JSON形式のTerraform設定(合成アセット)に「コンパイル(Synth)」し、それをTerraformエンジンに食わせるというアーキテクチャをとる。

  • 構造的欠陥: 抽象化のレイヤーが2枚重なっている点に注目してほしい。

`[CDKTFコード]` -> (`jsii` ランタイム) -> `[JSON]` -> (`Terraform Core`) -> (`Provider`) -> `[Cloud API]`
この構造により、デバッグ時に「どの層でエラーが起きたのか」の特定が困難になるケースが多い。特に大規模なループや条件分岐を書いた際、生成されるJSONのサイズが肥大化し、Terraform側のパース処理に深刻なオーバーヘッドを生む。

Pulumi:真のプログラミング言語駆動とgRPCプロバイダ

Pulumiは、HCLのような独自DSLを捨て、TypeScript, Go, Python, C#といった「本物のプログラミング言語」のランタイム上で直接実行される。

  • アーキテクチャの優位性: Pulumiのエンジンとリソースプロバイダは完全に分離されており、両者は gRPC で通信する。

これにより、インフラ定義の中で、通常のプログラミング言語の制御構文(非同期処理、外部APIの動的コール、高度なアルゴリズム)をそのままインフラ構築に組み込める。

  • ステート管理の柔軟性: Terraformが単一の巨大なJSONステートファイル(またはS3バックエンド)に依存するのに対し、PulumiはデフォルトでS3やGCSをバックエンドにしつつ、暗号化やトランザクション管理を言語ネイティブに処理する。

—

2. 状態管理(State)と冪等性(Idempotency)の限界突破

IaCの最大の悪夢は「ステートの破損」と「ロック競合」だ。ここでの挙動の違いは、障害時のリカバリ工数に直結する。

| 評価軸 | Terraform | CDKTF | Pulumi |
| :— | :— | :— | :— |
| ステートの本体 | JSON(Terraform State) | JSON(Terraform Stateと同一) | チェックサム付きJSON(Pulumi Service or 自前バックエンド) |
| 並行実行制御 | DynamoDB等によるState Locking | Terraformと同一(ロック機構依存) | プラットフォーム側 / バックエンド毎の楽観的ロック |
| 部分適用(Target) | `-target` あり(依存関係破壊のリスク大) | `cdktf diff/deploy` (Terraform依存) | `–target` / リソース単位のきめ細かな制御 |

Terraform / CDKTF のステート破壊リスク

Terraformのステートは単一の真実の源(Single Source of Truth)だが、同時に単一障害点(SPOF)でもある。大規模なリファクタリング(`moved` ブロックや `state mv`)を行う際、ステートファイルを手動でこねくり回した絶望的な経験を持つエンジニアは少なくないはずだ。

Pulumi のシークレット管理と動的ステート

Pulumiが頭一つ抜けているのは、リソースプロパティレベルでの暗号化(Secrets Management)が標準組み込みである点だ。
Terraformでは機密情報(DBパスワードなど)がプレーンテキストでステートに残るリスクがあり、Vaultなどの外部ツール連携が必須だった。一方、PulumiはKMSやHashiCorp Vault、AWS Secrets Manager等と連携し、コード内の特定の値だけを最初から暗号化してステートに保存できる。

// Pulumiでのシークレット明示的定義の例(TypeScript)
import as aws from “@pulumi/aws”;
import as pulumi from “@pulumi/pulumi”;

const dbPassword = new aws.rds.Instance(“my-db”, {
// この値は暗号化され、プレーンテキストとしてステートに露出しない
password: pulumi.secret(“SuperGeekSecretPassword123!”),
// …その他の設定
});

—

3. 開発言語の柔軟性とマルチクラウドの拡張性

インフラストラクチャが複雑化するにつれ、「単なるリソースの宣言」から「アプリケーションとインフラの統合オーケストレーション」へ要求がシフトしている。

GoによるPulumiカスタムプロバイダー / コンポーネントの極意

Pulumiの真骨頂は、ComponentResourceという概念を用いた「カスタム抽象化コンポーネント」の作成にある。
例えば、社内のセキュリティ基準を強制した「セキュアVPC」をGoやTypeScriptで自作し、パッケージとして社内ニッチに流通させることができる。CDKTFでもTerraform Moduleをラップできるが、汎用言語の強力な型システム(TypeScriptのGenericsやGoのインターフェース)を使えるPulumiの表現力には遠く及ばない。

以下は、Pulumiで「完全に型安全かつポリシー準拠したKubernetesクラスタ」を抽象化するコンポーネントの骨子だ。

package mycloud

import (
eks “github.com/pulumi/pulumi-aws/sdk/v6/go/aws/eks”
“github.com/pulumi/pulumi/sdk/v3/go/pulumi”
)

type SecureClusterArgs struct {
InstanceType pulumi.StringInput
MinSize pulumi.IntInput
}

type SecureCluster struct {
pulumi.ResourceState
Cluster eks.Cluster
}

func NewSecureCluster(ctx pulumi.Context, name string, args SecureClusterArgs, opts …pulumi.ResourceOption) (SecureCluster, error) {
instance := &SecureCluster{}
err := ctx.RegisterComponentResource(“mycloud:k8s:SecureCluster”, name, instance, opts…)
if err != nil {
return nil, err
}

// 厳格なセキュリティ規則を強制したEKS構築ロジックをカプセル化
// ここに社内コンプライアンス要件をハードコードし、開発者に自由度を与えつつ安全性を担保する

return instance, nil
}

このレベルの抽象化を行うと、もはや単なる設定ファイルではなく、「自社専用のインフラPaaSの構築」領域に突入する。これが可能なのはPulumiだけだ。

—

4. 現場の要件に応じた最適なツールの選び方 ― アーキテクトの最終裁定

では、我々プロフェッショナルはプロジェクトごとにどのツールを選択すべきか? 感情を排し、冷徹なアーキテクチャ判断を下す。

① Terraformを選ぶべきユースケース

  • インフラ専任チームが存在し、開発者がインフラコードに触れない場合。
  • HCLの枯れたエコシステム、圧倒的な数のモジュール(Terraform Registry)、そして「誰が書いても同じ書き方になる」という制約が強みになる。
  • マルチクラウドであっても、リソースの静的な宣言だけで完結する規模であれば、いまだにTerraform(またはOpenTofu)が最も安定した選択肢である。

② CDKTFを選ぶべきユースケース

  • すでに社内でTerraformの巨大なモジュール資産(HCL)が存在し、それを流用したい場合。
  • 開発フィールとしてTypeScriptやPythonを使いたいが、既存のTerraformプロバイダーエコシステム(Terraform Registryの全資産)を100%そのまま活かしたい移行期。
  • 注意: 新規プロジェクトでゼロからCDKTFを選ぶ理由は薄い。HCLとJSIIの二重管理コストに苦しむことになる。

③ Pulumiを選ぶべきユースケース

  • 「インフラとアプリケーションの境界線」を破壊し、完全に統合されたシステムを構築したい場合。
  • Kubernetesのマニフェスト生成、AWSリソースの動的プロビジョニング、テスト駆動開発(TDD)によるインフラテスト、CI/CDパイプラインからの直接制御を高度に行うSREチーム。
  • 特に、「動的な処理(例:AWS APIを叩いて最新のAMI IDを動的に取得し、セキュリティグループと動的にバインドする)」をエレガントにやりたいなら、HCLの貧弱な関数群で消耗するより、Pulumi(TypeScript/Go)を選ぶべきだ。

—

5. 結論:ツールに縛られるな、アーキテクチャを支配せよ

どのツールを選ぶにせよ、真に重要なのは「コードの美しさ」ではなく、「障害時にステートが破損した際、どれだけ迅速に復旧できるか」「自動化パイプラインがどれだけ予測可能で堅牢か」という一点に尽きる。

Terraformは宗教的なまでの「宣言的安定性」を我々に教えてくれた。
CDKTFは「汎用言語による抽象化の夢」を見せた。
そしてPulumiは、「インフラストラクチャを本当の意味でソフトウェアとして扱う」ための極限の自由度とエンジニアリングの楽しさを提供している。

自らの組織の成熟度、メンバーのスキルセット、そしてシステムの複雑性を見極め、最適なエンジンをその手で選択し、完全に掌握してほしい。技術の限界を突破するのは、いつだって仕様書ではなく、我々エンジニアの執念なのだから。

タイトルとURLをコピーしました