CDK・Terraform・Pulumi、3年本番運用して見えた本当の選び方
「比較記事を読んでも結局どれを選べばいいかわからない」と困ったことありませんか?3年間3ツールを本番運用した経験から、チーム規模・学習コスト・State管理の観点で正直に書きます。
CDK vs Terraform vs Pulumi、3年本番運用して見えた本当の選び方2026年版
正直に言う。3年前、うちのチームがIaCツールを選ぶときに「比較記事」を30本くらい読んだけど、ほとんど役に立たなかった。どれも「それぞれの特徴」を並べてあるだけで、「で、どれ選べばいいの?」という問いに答えてくれる記事がなかったんですよね。
それから3年、CDKをメインにしつつTerraformのレガシーも運用し、一時期Pulumiを本番サービスに導入するという珍しい経歴を積んだ。失敗も含めてかなり見えてきたものがあるので、今日はその知見を正直に書く。
なお、Terraformの3年分の失敗については別記事に詳しく書いたので、そちらも参照してほしい → Terraformで3年分の失敗から学んだ、State管理とAI検証の正解
2026年時点での各ツールの立ち位置
まず現状把握から。2026年のIaCシーンはけっこう変わった。
AWS CDKはv2が完全に安定期に入り、CDK Migrateで既存CloudFormationリソースを取り込む機能が実用レベルになった。CDK Migrate で200個のAWSリソースを一元化した話でも書いたが、レガシーリソースの取り込みがかなり楽になっている。また、CDK Aspects + cdk-nagによるセキュリティ自動検証が実務で定着してきた。
TerraformはHashiCorp買収後の混乱(OpenTofuへのフォーク騒動)がひと段落し、2026年時点ではOpenTofu 1.9系が企業採用を増やしている。BSL問題を懸念する組織はOpenTofuへ、そうでない組織は引き続きTerraformを選ぶという二極化が進んだ印象だ。
PulumiはAI統合(Pulumi Copilot)が本格化し、自然言語でインフラを記述してTypeScriptコードを生成する機能が実用的になっている。個人的には「一番将来性を感じるが、一番学習リソースが少ない」という印象が変わっていない。
| ツール | バージョン(2026/8時点) | ライセンス | 主な変化 |
|---|---|---|---|
| AWS CDK | v2.155+ | Apache 2.0 | CDK Migrate GA・cdk-nag強化 |
| Terraform | 1.9.x | BSL 1.1 | OpenTofuと二極化 |
| OpenTofu | 1.9.x | MPL 2.0 | Terraformフォーク・互換性維持 |
| Pulumi | 3.130+ | Apache 2.0 | Copilot統合・AI補完強化 |
実際に3年使って見えたメリット・デメリット
ここが本題。スペック表じゃなくて「運用してわかった話」を書く。
AWS CDK:AWSオンリーなら本当に強い
// CDK v2 - L3コンストラクトの威力
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { ApplicationLoadBalancedFargateService } from 'aws-cdk-lib/aws-ecs-patterns';
export class MyServiceStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const vpc = new ec2.Vpc(this, 'VPC', {
maxAzs: 2,
natGateways: 1,
});
// L3コンストラクト1行でALB+ECS+AutoScaling+IAMロールがセットで作れる
const service = new ApplicationLoadBalancedFargateService(this, 'Service', {
vpc,
cpu: 512,
memoryLimitMiB: 1024,
desiredCount: 2,
taskImageOptions: {
image: ecs.ContainerImage.fromRegistry('nginx'),
containerPort: 80,
},
publicLoadBalancer: true,
});
// スケーリングも直感的
service.scalableTaskCount.scaleOnCpuUtilization('CpuScaling', {
targetUtilizationPercent: 70,
scaleInCooldown: cdk.Duration.seconds(60),
scaleOutCooldown: cdk.Duration.seconds(60),
});
}
}
これ、Terraformで書くと100行超える。CDKのL3コンストラクトの威力は本物で、特にAWSのベストプラクティスが暗黙的に組み込まれているのが地味に強い。
ただし、CloudFormationのデプロイ速度問題は2026年になっても根本解決していない。大規模スタックだと1デプロイ20〜30分かかることがある。ここはマジでストレスになる。
実際に困ったこと: スタックをまたいだ依存関係が複雑になると、デプロイ順序の管理が地獄になる。CDK Pipelinesを使えば多少マシになるが、それはそれで学習コストがかかる。ベストプラクティスに従ってスタックを細かく分割したら分割したで、今度はクロススタック参照がカオスになるというジレンマも経験した。
Terraform/OpenTofu:マルチクラウドとチーム運用の定番
# Terraform 1.9.x - テスト機能が強化された
terraform {
required_version = ">= 1.9.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.60"
}
}
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "ap-northeast-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# 1.9から強化されたephemereral resourcesの活用
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(local.common_tags, {
Name = "${var.env}-main-vpc"
})
}
# 組み込みテスト機能(1.6〜)
check "vpc_cidr_check" {
assert {
condition = can(cidrhost(aws_vpc.main.cidr_block, 0))
error_message = "VPC CIDR block is not valid."
}
}
Terraformの強みは「状態管理の思想が明確」なこと。terraform plan で差分が見えて、terraform apply で適用、terraform destroy で削除。この一貫性は、チームの規模が大きくなるほど効いてくる。
実際、うちのチームで10人を超えたあたりから「CDKよりTerraformのほうが読みやすい」という意見が出るようになった。TypeScriptが得意じゃないメンバーでも、HCLは比較的読めるんですよね。慣れればPRレビューもしやすいし、意図せぬ変更に気づきやすい。
OpenTofuについては、Terraform 1.6〜1.9の機能をほぼ完全に移植できている。BSLが気になる組織はOpenTofuへの移行を検討していい段階だと思う。
Pulumi:TypeScript派には本当にいいが、エコシステムが課題
// Pulumi - TypeScriptでAWSインフラを書く
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";
const config = new pulumi.Config();
const env = config.require("env");
// 通常のTypeScriptの型安全性がそのまま使える
const vpc = new aws.ec2.Vpc("main", {
cidrBlock: "10.0.0.0/16",
enableDnsHostnames: true,
enableDnsSupport: true,
tags: { Name: `${env}-main-vpc`, Environment: env },
});
// 非同期処理を自然に書けるのが強い
const latestAmi = aws.ec2.getAmi({
mostRecent: true,
owners: ["amazon"],
filters: [{ name: "name", values: ["amzn2-ami-hvm-*-x86_64-gp2"] }],
});
// Pulumi Copilot(2026年版)でAI補完が強化された
const instance = new aws.ec2.Instance("web", {
ami: latestAmi.then(ami => ami.id),
instanceType: "t3.micro",
subnetId: publicSubnet.id,
tags: { Name: `${env}-web` },
});
export const instancePublicIp = instance.publicIp;
Pulumiの「TypeScriptがそのまま使える」というのは本当にそう。ループ、条件分岐、関数、すべてが普通のTypeScriptで書けるので、複雑なロジックを表現しやすい。コードを書いていて一番「気持ちいい」のは正直Pulumiだった。
ただし、Pulumi Stateのバックエンドに Pulumi Cloud(SaaS)を使うか自前でS3を使うかの選択が意外と面倒だった。また、トラブル時に参照できる日本語情報がTerraform比で圧倒的に少ない。2026年になってもこの課題は解決していない。はまったときに英語のGitHub Issuesを掘り続ける体力が必要で、それがチームに伝わるかどうかがPulumiを本番採用するかどうかの分岐点になると思う。
実際に構築した本番構成
今うちのチームがCDKで管理しているマルチアカウント・マルチAZ構成を図にした。
graph TB
subgraph "Management Account"
CDKPipelines[CDK Pipelines]
CodePipeline[CodePipeline V2]
CDKPipelines --> CodePipeline
end
subgraph "Production Account"
subgraph "VPC 10.0.0.0/16"
subgraph "AZ-a ap-northeast-1a"
ALBa[ALB Target]
ECSa[ECS Fargate Task]
RDSa[(RDS Aurora Primary)]
ALBa --> ECSa
ECSa --> RDSa
end
subgraph "AZ-c ap-northeast-1c"
ALBc[ALB Target]
ECSc[ECS Fargate Task]
RDSc[(RDS Aurora Replica)]
ALBc --> ECSc
ECSc --> RDSc
end
ALB[Application Load Balancer]
ALB --> ALBa
ALB --> ALBc
RDSa -.レプリケーション.-> RDSc
subgraph "Private Subnet"
SecretsManager[Secrets Manager]
SSM[SSM Parameter Store]
ECSa --> SecretsManager
ECSc --> SecretsManager
end
end
CloudFront[CloudFront]
WAF[WAF v2]
CloudFront --> WAF
WAF --> ALB
end
subgraph "Shared Services Account"
ECR[ECR]
S3State[S3 CDK Assets]
end
CodePipeline -->|クロスアカウントデプロイ| ALB
CodePipeline --> ECR
ECSa --> ECR
ECSc --> ECR
この構成、CDKで管理していて本当に良かったと思うのは、新しいサービスを追加するときにL3コンストラクトを1つ追加するだけで済むこと。Terraformでやろうとすると、新サービス追加のたびにモジュールの設計を考え直す必要があった。
選定基準をフローで整理した
「で、結局どれ選べばいいの」という問いへの答えを、判断フローにまとめてみた。
flowchart TD
Start([IaCツール選定開始]) --> Q1{AWSオンリーか?}
Q1 -->|Yes| Q2{チームの主言語は?}
Q1 -->|No マルチクラウド| TF[Terraform / OpenTofu を選ぶ]
Q2 -->|TypeScript/Python| Q3{既存CFnリソースが大量にあるか?}
Q2 -->|HCLでもOK / 未経験多い| TF
Q3 -->|Yes 移行コストが怖い| Q4{CDK Migrateで対応できるか?}
Q3 -->|No 新規プロジェクト| CDK[AWS CDK を選ぶ]
Q4 -->|Yes| CDK
Q4 -->|No 複雑すぎる| TF
TF --> Q5{ライセンス懸念があるか?}
Q5 -->|Yes BSLが嫌| OTF[OpenTofu を選ぶ]
Q5 -->|No 問題ない| TFF[Terraform を選ぶ]
CDK --> R1[CDK Pipelines + cdk-nagで運用]
OTF --> R2[OpenTofu + Atlantisで運用]
TFF --> R3[Terraform Cloud or S3バックエンドで運用]
R1 --> End([運用開始])
R2 --> End
R3 --> End
このフローで「Pulumi」が出てこないのは意図的だ。決して悪いツールじゃないんだけど、「迷ったらPulumi」にできるほど情報が揃っていないのが正直なところで、積極的に勧めるのは現時点では難しい。
3ツールのスコア比較と移行コスト
実務的な評価軸でスコアリングしてみた。あくまで主観込みの評価なので、参考程度に。
| 評価軸 | AWS CDK | Terraform | OpenTofu | Pulumi |
|---|---|---|---|---|
| AWSリソース作成の簡単さ | ★★★★★ | ★★★☆☆ | ★★★☆☆ | ★★★★☆ |
| マルチクラウド対応 | ★☆☆☆☆ | ★★★★★ | ★★★★★ | ★★★★☆ |
| 学習コスト(初心者) | ★★★☆☆ | ★★★★☆ | ★★★★☆ | ★★☆☆☆ |
| チーム運用のしやすさ | ★★★☆☆ | ★★★★★ | ★★★★★ | ★★☆☆☆ |
| デプロイ速度 | ★★☆☆☆ | ★★★★☆ | ★★★★☆ | ★★★★☆ |
| エコシステム・情報量 | ★★★★☆ | ★★★★★ | ★★★☆☆ | ★★☆☆☆ |
| AI補完・開発体験 | ★★★★☆ | ★★★☆☆ | ★★★☆☆ | ★★★★★ |
| コスト(OSS利用時) | 無料 | 無料 | 無料 | 無料 |
| コスト(CI/CD統合) | 要検討 | Terraform Cloud有料 | 無料 | Pulumi Cloud有料 |
デプロイ速度についてはもう少し補足すると、体感でこんな感じだった。
xychart-beta
title "平均デプロイ時間比較(リソース数50個のスタック・分)"
x-axis ["CDK (CFn経由)", "Terraform", "OpenTofu", "Pulumi"]
y-axis "デプロイ時間(分)" 0 --> 25
bar [22, 8, 8, 9]
CDKのデプロイが遅いのはCloudFormationの宿命みたいなもので、2026年になっても劇的な改善はなかった。ただし、CDK Hotswapを使えば変更内容によっては1〜2分で終わるので、開発中はこれを使い倒している。Lambda関数やECSタスク定義の更新ならHotswapがほぼ効くので、実際の開発体験はスコアほど悪くない。
実際に失敗した話と、今うちがやっていること
正直まだ「これが完璧」という構成はないんだけど、3年の試行錯誤を経て今のうちのチームはこうしている。
AWSリソースのメイン管理 → CDK v2 L3コンストラクトの恩恵が大きいので、AWS専用のインフラはCDKで書いている。cdk-nagを必ずCIに組み込んで、セキュリティチェックを自動化している。この辺の詳細はCDK Aspects・Nag本番導入3ヶ月で気づいた、自動セキュリティ検証の現実に書いた。
データ基盤・マルチクラウド連携 → OpenTofu Athena、Glue、Redshiftまわりはデータエンジニアもコードを書くことがあって、HCLのほうが読みやすいという意見が多かった。あとBSLへの懸念からOpenTofuに切り替えた。切り替え自体は思ったより楽で、ほぼコピーで移行できた。
実験的なサービス → Pulumi AI補完(Pulumi Copilot)を使った新規サービス構築の検討に使っている。ただ正直、まだ本番のメイン管理に使うのは怖い。情報が少なくて、はまったときの解決に時間がかかるので。
# CDKのデプロイフロー(実際のCI設定抜粋)
# .github/workflows/deploy.yml
jobs:
deploy:
steps:
- name: Install dependencies
run: npm ci
- name: Run cdk-nag checks
run: npx cdk synth --strict
- name: Run CDK tests
run: npx jest --coverage
- name: Deploy to staging
run: npx cdk deploy --all --require-approval never
env:
CDK_DEPLOY_ACCOUNT: ${{ secrets.STAGING_ACCOUNT_ID }}
CDK_DEPLOY_REGION: ap-northeast-1
- name: Integration test
run: npm run test:integration
- name: Deploy to production
if: github.ref == 'refs/heads/main'
run: npx cdk deploy --all --require-approval never
env:
CDK_DEPLOY_ACCOUNT: ${{ secrets.PROD_ACCOUNT_ID }}
CDK_DEPLOY_REGION: ap-northeast-1
# OpenTofu(Terraform)のState管理確認コマンド
# 運用3年でよく使うコマンドたち
# 現在のStateリスト確認
tofu state list
# 特定リソースの詳細
tofu state show aws_vpc.main
# ドリフト検出(差分確認)
tofu plan -detailed-exitcode
# リモートStateのロック確認
tofu force-unlock <LOCK_ID> # 緊急時のみ
# Stateをバックアップしてから移動
tofu state mv aws_instance.old aws_instance.new
tofu force-unlock は「緊急時のみ」と書いたが、本当に緊急時だけにしてほしい。CI/CDが途中で死んでロックが残ったとき以外に使うと、State壊滅の可能性がある。経験者は語る。
皆さんはどうしてます?マルチクラウド構成がないAWS専任チームでもTerraformを選ぶ理由って、やはりチームの学習コスト面が大きいんだろうか。
マルチクラウド運用の全体像についてはマルチクラウド戦略2026|最適構成とベストプラクティスも参考になるので、合わせて読んでほしい。
まとめ
3年本番で使い続けて辿り着いたのは「銀の弾丸はない」という当たり前の結論だった。ただ、判断基準は整理できた。
要点3つ:
-
AWSオンリーでチームがTypeScript/Python得意なら迷わずCDK。L3コンストラクトの開発体験は本物。ただしデプロイ速度の遅さは覚悟する。
-
マルチクラウドや大人数チームはTerraform/OpenTofu。HCLの読みやすさとState管理の明確さはチームが大きくなるほど効いてくる。BSL懸念があればOpenTofuに移行を検討。
-
Pulumiは「TypeScript大好き」かつ「情報不足を自力で解決できる」チーム向け。AI補完(Copilot)の進化は本物なので、2〜3年後には逆転しているかもしれないとは思っている。
次のアクション:
- 既存プロジェクトのIaCを見直す前に、まずチームの技術スタックと人員構成を確認する
- CDKを使うなら cdk-nag を最初から組み込む(後から入れると地獄)
- TerraformユーザーはOpenTofuの移行コストを見積もっておく(BSLが今後どうなるか不透明なため)
- どのツールでも「State管理」と「ドリフト検出」の仕組みを最初に設計すること
正直、ツール選びより「どうState管理するか」「どうドリフトを検出するか」を設計するほうが100倍重要だった。そこさえ整っていれば、どのツールを選んでも大きく失敗することはないと思う。