Pulumi vs Terraform 2026年版:TypeScriptによるInfrastructure as Codeと面接対策

2026年版PulumiとTerraform比較ガイド。TypeScriptサポート、状態管理、プロバイダエコシステム、移行戦略、DevOps面接質問を解説します。

Pulumi vs Terraform 2026年版:TypeScriptによるInfrastructure as Codeと面接対策

PulumiとTerraformは、2026年のDevOpsチームにとってInfrastructure as Code(IaC)における中心的な選択肢である。両ツールはクラウドリソースを宣言的にプロビジョニングするが、言語サポート、状態管理、エコシステムの成熟度において大きく異なる。本記事では、技術的なトレードオフ、TypeScriptとHCLによるコード例、IaC選択に関する面接質問を詳しく解説する。

バージョン情報:2026年9月時点

本比較では、Pulumi v3.263.0(2026年9月15日リリース)とTerraform 1.16.3(2026年8月26日リリース)を使用している。HashiCorpのTypeScriptレイヤーであるCDKTFは2025年12月に非推奨となり、アーカイブされている。

コアアーキテクチャ:PulumiエンジンとTerraformのPlan-Applyサイクル

Terraformはドメイン固有言語(HCL)と2フェーズのワークフローを採用している。terraform planが実行計画を生成し、terraform applyがそれを実行する。状態ファイルはリソースメタデータを追跡し、ローカルまたはS3やTerraform Cloudなどのリモートバックエンドに保存される。

Pulumiは汎用ランタイムにエンジンを組み込んでいる。TypeScript、Python、Go、C#で書かれたプログラムは、Pulumiプロバイダを通じてクラウドAPIに直接アクセスする。状態はデフォルトでPulumi Cloudに保存されるが、S3、Azure Blob Storage、ローカルファイルなどの自己管理バックエンドも選択可能である。

アーキテクチャの違いは、ループ、条件分岐、抽象化の扱い方に直接現れる。Terraformのfor_eachとcountはHCLの制約内で動作する。Pulumiプログラムはネイティブ言語構文を使用する:TypeScriptのfor...of、Pythonのリスト内包表記、Goのrangeなどである。

infra/index.ts - Pulumi TypeScriptの例typescript
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";

// ネイティブTypeScript配列メソッドが直接使用可能
const environments = ["dev", "staging", "prod"];

const buckets = environments.map(env => 
  new aws.s3.BucketV2(`data-${env}`, {
    bucket: `myapp-data-${env}-${pulumi.getStack()}`,
    tags: {
      Environment: env,
      ManagedBy: "pulumi",
    },
  })
);

// バケットARNをスタック出力としてエクスポート
export const bucketArns = buckets.map(b => b.arn);

同等のTerraform設定では、イテレーションにHCL構文が必要となる:

hcl
# main.tf - Terraform HCLの例
variable "environments" {
  type    = list(string)
  default = ["dev", "staging", "prod"]
}

resource "aws_s3_bucket" "data" {
  for_each = toset(var.environments)

  bucket = "myapp-data-${each.key}-${terraform.workspace}"

  tags = {
    Environment = each.key
    ManagedBy   = "terraform"
  }
}

output "bucket_arns" {
  value = [for b in aws_s3_bucket.data : b.arn]
}

両方のスニペットは3つのS3バケットを作成する。Terraform版はHCLに慣れた人にとって簡潔で読みやすい。Pulumi版は標準的なTypeScriptを使用するため、IDE自動補完、型チェック、既存コードベースとの統合が可能であり、新しい言語を学ぶ必要がない。

TypeScriptサポート:ネイティブ言語 vs CDKTF(非推奨)

Pulumiは初回公開リリースからTypeScriptをサポートしている。SDKは型付きリソースクラスを提供し、pulumi.Output<T>はデプロイ中に解決される非同期値をラップする。TypeScriptエコシステムのリファクタリングツール、リンター、テストフレームワークが直接適用可能である。

Terraformの汎用言語サポートへの回答はCDKTF(Cloud Development Kit for Terraform)であった。CDKTFはTypeScriptまたはPythonでTerraform JSONにコンパイルされるコードを記述可能にした。HashiCorpは2025年12月にCDKTFを非推奨とし、リポジトリをアーカイブした。既存のCDKTFプロジェクトは引き続き動作するが、新しいTerraformバージョンやプロバイダ変更への更新は提供されない。

2026年にTypeScript IaCを求めるチームにとって、Pulumiが積極的にメンテナンスされている選択肢である。CDKTFに既に投資しているチームは既存スタックを継続運用できるが、新規開発ではHCLまたはPulumiへの移行が前進への道となる。

infra/vpc.ts - 再利用可能なVPC抽象化のためのPulumiコンポーネントtypescript
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";

// VPC、サブネット、ルーティングをカプセル化したカスタムコンポーネント
export class StandardVpc extends pulumi.ComponentResource {
  public readonly vpcId: pulumi.Output<string>;
  public readonly publicSubnetIds: pulumi.Output<string>[];

  constructor(name: string, args: { cidr: string; azCount: number }, opts?: pulumi.ComponentResourceOptions) {
    super("mycompany:network:StandardVpc", name, {}, opts);

    const vpc = new aws.ec2.Vpc(`${name}-vpc`, {
      cidrBlock: args.cidr,
      enableDnsHostnames: true,
      tags: { Name: name },
    }, { parent: this });

    this.vpcId = vpc.id;

    // アベイラビリティゾーン全体にパブリックサブネットを作成
    const azs = aws.getAvailabilityZones({ state: "available" });
    this.publicSubnetIds = [];

    for (let i = 0; i < args.azCount; i++) {
      const subnet = new aws.ec2.Subnet(`${name}-public-${i}`, {
        vpcId: vpc.id,
        cidrBlock: `10.0.${i}.0/24`,
        availabilityZone: azs.then(az => az.names[i]),
        mapPublicIpOnLaunch: true,
        tags: { Name: `${name}-public-${i}` },
      }, { parent: this });
      this.publicSubnetIds.push(subnet.id);
    }

    this.registerOutputs({ vpcId: this.vpcId });
  }
}

このPulumiコンポーネントは再利用可能なVPC抽象化を作成する。利用者はnew StandardVpc("prod", { cidr: "10.0.0.0/16", azCount: 3 })でインスタンス化する。Terraformでの同等の実装は、変数、出力、HCLファイルを含むモジュールディレクトリとなる。両アプローチとも再利用を可能にするが、Pulumi版はドキュメント、テスト、バージョニングのためのTypeScriptツールを継承する。

状態管理とバックエンドオプション

状態管理は運用上の違いが現れる領域である。Terraform状態にはリソースID、プロバイダメタデータ、機密値が含まれる。チームはコラボレーションを可能にするためにリモートバックエンドを設定し、同時変更を防ぐためにロックを実装する必要がある。

Terraformバックエンド設定はS3、Azure Blob、Google Cloud Storage、Terraform Cloudなどをサポートする。各バックエンドには独自の認証設定が必要である。状態ロックはS3バックエンドではDynamoDB、AzureではBlobリース、Terraform Cloudではネイティブロックを使用する。

Pulumi Cloudはデフォルトで状態ストレージ、ロック、履歴を処理する。チームは無料アカウントを作成し、pulumi loginを実行するだけで状態管理が設定される。自己管理状態を必要とするチームのために、PulumiはS3、Azure Blob、GCS、ローカルファイルバックエンドをpulumi loginコマンドでサポートする。

bash
# Pulumi: 自己管理S3バックエンドにログイン
pulumi login s3://my-pulumi-state-bucket

# Terraform: HCLでS3バックエンドを設定
# backend.tf
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

Pulumi Cloudはスタック履歴、リソース可視化、チーム権限のためのWebUIを提供する。Terraform CloudはSentinelを通じたポリシー適用と同様の機能を提供する。両方にセルフホストオプションが存在する:Pulumiのセルフホストバックエンドとterraform Enterpriseである。

DevOpsの面接対策はできていますか?

インタラクティブなシミュレーター、flashcards、技術テストで練習しましょう。

プロバイダエコシステムとマルチクラウドサポート

TerraformのプロバイダエコシステムはIaC最大である。Terraform RegistryにはAWS、Azure、GCP、Kubernetesおよび数百のSaaSプラットフォームをカバーする4,000以上のプロバイダが登録されている。プロバイダ品質は様々で、HashiCorp公式およびクラウドベンダープロバイダは定期的に更新されるが、コミュニティプロバイダはAPI変更に追従できない場合がある。

Pulumiプロバイダは、型付きSDKを生成するブリッジを使用してTerraformプロバイダをラップする。Pulumi Registryは主要クラウド、Kubernetes、データベース、モニタリングサービス用のプロバイダを提供する。PulumiがTerraformプロバイダをブリッジするため、エコシステムカバレッジは同等であるが、新しいTerraformプロバイダバージョンはPulumi SDKに反映される前にブリッジ更新が必要となる。

PulumiはクラウドAPIに対して直接記述されたネイティブプロバイダも提供する。AWS、Azure、Kubernetesのネイティブプロバイダは新しいAPI機能を当日サポートする。トレードオフとして、ネイティブプロバイダは主要クラウドにのみ存在し、一般的でないサービスはブリッジプロバイダを使用する。

typescript
// PulumiのネイティブAWSプロバイダを使用したLambda
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";

const role = new aws.iam.Role("lambda-role", {
  assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({
    Service: "lambda.amazonaws.com",
  }),
});

const lambdaFunction = new aws.lambda.Function("api-handler", {
  runtime: aws.lambda.Runtime.NodeJS20dX,
  handler: "index.handler",
  role: role.arn,
  code: new pulumi.asset.AssetArchive({
    "index.js": new pulumi.asset.StringAsset(
      `exports.handler = async () => ({ statusCode: 200, body: "OK" });`
    ),
  }),
});

export const functionArn = lambdaFunction.arn;

インフラストラクチャコードのテスト

テストは言語選択による分岐が生じる領域である。Pulumiプログラムは標準的なコードであるため、ユニットテストには慣れたフレームワークを使用できる。@pulumi/pulumi/runtimeモジュールはリソース作成のモックを提供し、リソースをデプロイせずに設定を検証できる。

__tests__/infra.test.ts - VitestによるPulumiリソースのユニットテストtypescript
import { describe, it, expect, beforeAll } from "vitest";
import * as pulumi from "@pulumi/pulumi";

// Pulumiランタイムをモック
pulumi.runtime.setMocks({
  newResource: (args: pulumi.runtime.MockResourceArgs) => {
    return { id: `${args.name}-id`, state: args.inputs };
  },
  call: (args: pulumi.runtime.MockCallArgs) => {
    return args.inputs;
  },
});

describe("S3バケット設定", () => {
  let bucketTags: Record<string, string>;

  beforeAll(async () => {
    // モック設定後にPulumiプログラムをインポート
    const infra = await import("../infra/index");
    // テスト用に出力を抽出
    bucketTags = await new Promise(resolve => {
      infra.buckets[0].tags.apply(tags => resolve(tags as Record<string, string>));
    });
  });

  it("バケットにEnvironmentタグが設定されていること", () => {
    expect(bucketTags).toHaveProperty("Environment");
  });

  it("バケットにManagedByタグが設定されていること", () => {
    expect(bucketTags.ManagedBy).toBe("pulumi");
  });
});

Terraformテストはterraform test(Terraform 1.6で導入)またはTerratestなどの外部ツールを使用する。terraform testは分離された設定で実際のリソースを作成するHCLテストファイルを実行する。TerratestはTerraformコマンドをラップしアサーションを提供するGoライブラリである。

hcl
# tests/bucket.tftest.hcl - Terraformネイティブテスト
run "bucket_tags" {
  command = plan

  assert {
    condition     = aws_s3_bucket.data["dev"].tags["Environment"] == "dev"
    error_message = "バケットにEnvironmentタグが必要です"
  }

  assert {
    condition     = aws_s3_bucket.data["dev"].tags["ManagedBy"] == "terraform"
    error_message = "バケットにManagedByタグが必要です"
  }
}

両アプローチともインフラストラクチャ設定を検証する。Pulumiの利点はTypeScriptテストランナーとカバレッジツールとの統合である。Terraformネイティブテストは外部依存なしで実行されるが、HCL構文が必要である。

面接質問:Pulumi vs Terraform

2026年のDevOps面接ではIaCツール比較が頻繁に含まれる。以下は本番環境で両ツールを使用した候補者を見分ける質問である。

「Terraform状態が実際のインフラストラクチャからドリフトした場合、何が起こりますか?」

期待される回答:terraform planは状態と実際のインフラストラクチャを比較してドリフトを検出する。プランは更新、作成、削除するリソースを表示する。ドリフトはTerraform外で変更が行われた場合(コンソール、CLI、他のツール)に発生する。オプションには状態を更新するterraform refresh、リソースを管理下に置くterraform import、または望ましい状態を復元するプランの承認がある。

「PulumiはTerraformと比較してシークレットをどのように異なる方法で扱いますか?」

期待される回答:PulumiはパスフレーズまたはクラウドKMSを使用してデフォルトで状態内のシークレットを暗号化する。pulumi.secret()関数は値を機密としてマークし、保存時に暗号化されたままとなる。Terraformは状態ファイル内でシークレットを平文で保存し、チームはバックエンド暗号化(S3サーバーサイド暗号化)とアクセス制御に依存する。Terraform 1.4ではsensitive変数マーキングが追加されたが、値は状態内で暗号化されずに表示される。

「HashiCorpがCDKTFを非推奨にした理由と、移行オプションは何ですか?」

期待される回答:CDKTFはTerraformの更新サイクルに追従できないままメンテナンスオーバーヘッドを追加した。新しいプロバイダバージョンとTerraform機能にはCDKバインディングへの手動更新が必要だった。HashiCorpはHCLとTerraform Cloudに注力することを選択した。移行オプションは:cdktf convertを使用してHCLに変換する、TypeScriptが必要な場合はPulumiで書き直す、または更新なしで既存CDKTFスタックを継続運用する。

「新規プロジェクトでTerraformよりPulumiを選択するのはどのような場合ですか?」

期待される回答:チームが既にTypeScript/Python/Goを使用しており、アプリケーションコードと同じ言語でIaCを記述したい場合、複雑な抽象化に実際のプログラミング構文(ジェネリクス、インターフェース、テストフレームワーク)が必要な場合、または組み込みのシークレット暗号化が要件の場合にPulumiを選択する。チームがHCLを知っている場合、プロバイダエコシステムにニッチまたはコミュニティプロバイダが必要な場合、または組織ツール(Atlantis、Spacelift)がTerraformと統合している場合にTerraformを選択する。

Infrastructure as Codeの面接準備の詳細については、Terraform面接質問:Infrastructure as Code完全ガイドおよびTerraform上級モジュールを参照のこと。

移行戦略:TerraformからPulumiへ

Pulumiはpulumi importを提供し、既存のクラウドリソースを再作成せずに管理下に置くことができる。Terraform状態を持つチーム向けに、pulumi convertはHCLをPulumiプログラムに変換する。変換は完璧ではなく、複雑なモジュールやダイナミックブロックには手動調整が必要である。

bash
# Terraform HCLをPulumi TypeScriptに変換
pulumi convert --from terraform --language typescript

# 既存AWSリソースをPulumi状態にインポート
pulumi import aws:s3/bucketV2:BucketV2 my-bucket my-existing-bucket-name

段階的移行により、チームは移行期間中に両ツールを運用できる。Terraformが既存スタックを管理し、Pulumiが新規インフラストラクチャをプロビジョニングする。チームがPulumiの経験を積んだ後、Terraformスタックを段階的に変換する。状態はツール間で共有されないため、競合を避けるためにリソース管理を明確に分割する必要がある。

2026年の意思決定フレームワーク

要素TerraformPulumi
言語HCL(DSL)TypeScript、Python、Go、C#、Java、YAML
状態管理自己管理またはTerraform CloudPulumi Cloud(デフォルト)または自己管理
シークレット処理状態内で平文、バックエンド暗号化デフォルトで暗号化
テストterraform test、Terratestネイティブ言語テストフレームワーク
プロバイダカバレッジレジストリに4,000以上Terraformプロバイダをブリッジ + ネイティブSDK
TypeScriptサポートCDKTF(2025年12月非推奨)ファーストクラス、積極的にメンテナンス
学習曲線HCLは専用設計、IaCには素早い既存言語知識が必要
エンタープライズ機能Terraform Cloud/EnterprisePulumi Cloud/セルフホスト
面接のヒント

Pulumi vs Terraformについて質問されたとき、一方が「より良い」と述べることを避ける。トレードオフを明確にする:Terraformはより大きなエコシステムを持ち、HCLの制約がランタイムエラーを防ぐ。Pulumiは実際の言語機能と型付きSDKを提供する。選択はチームスキル、既存ツール、プロジェクト要件に依存することを示す。

2026年のInfrastructure as Codeの重要ポイント

  • Terraform 1.16は最大のプロバイダエコシステムと成熟したツール(Atlantis、Spacelift、env0)を持つHCLベースIaCの安定した選択肢である。
  • Pulumi v3.263はTypeScript、Python、Go、C#をネイティブ言語テスト、IDE統合、組み込みシークレット暗号化とともに提供する。
  • CDKTFは2025年12月以降非推奨である。TypeScript IaCを求めるチームは新規CDKTFプロジェクトを開始するよりPulumiを評価すべきである。
  • 両ツールともマルチクラウドデプロイメント、リモート状態バックエンド、チームコラボレーションをサポートする。選択は言語の好みと既存チームの専門知識に依存する。
  • 面接での議論では、状態管理、ドリフト検出、プロバイダエコシステム、DSLの簡潔さと汎用言語のパワー間のトレードオフの理解を示すべきである。
  • TerraformからPulumiへの移行はpulumi convertとpulumi importを使用して可能であるが、慎重な計画と段階的なロールアウトが必要である。

今すぐ練習を始めましょう!

面接シミュレーターと技術テストで知識をテストしましょう。

今日のチャレンジ

DevOps のバグを見つけられますか

実際のコード、隠れたバグ、1日1回。アカウントなしで試せます。

Anthony Fillion-Maillet

執筆

Anthony Fillion-Maillet

SharpSkill 創業者

10 年以上フルスタック開発に携わっています。SharpSkill を運営し、ここで公開される内容に責任を負っています。

2026年9月21日 更新

共有

関連記事