PulumiとTerraformのstate競合を防ぐ|並走期間中のリソース所有権の分け方

運営:リナックスマスター.JP(代表 宮崎智広)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Terraform > PulumiとTerraformのstate競合を防ぐ|並走期間中のリソース所有権の分け方
「TerraformからPulumiへの移行を始めたら、どちらのツールが管轄するリソースかわからなくなってきた」
「terraform applyを打ったら、Pulumiで作ったリソースまで変更対象に入っていた」

この記事では、TerraformとPulumiを並走させる「移行期」に発生するstate競合の仕組みと、リソース所有権を明確に分ける設計パターンを解説します。RHEL 9系 / Ubuntu 24.04 LTS を想定環境として説明します。

この記事のポイント

・PulumiとTerraformはstateストアが独立しているため「二重所有」が無音で起きる
・terraform state rmとpulumi importを使えばリソース移管は安全に行える
・prevent_destroyとignore_changesで誤操作の影響範囲を限定できる
・ディレクトリとCIゲートで所有権を可視化することが長期運用の要点


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

なぜTerraformとPulumiのstate競合が問題になるのか

TerraformはHCLで記述した構成をtfstateファイルに記録し、そのstateと実際のクラウドリソースとの差分をもとに変更計画(plan)を生成します。PulumiはTypeScript・Python等の汎用言語でインフラを定義し、独自のstateバックエンド(デフォルトはPulumi Cloud、セルフホスト時はS3等)に状態を保存します。

この2つはstateストアが完全に独立しているため、同じAWSリソースを両方のツールが「自分が管理している」と記録できてしまいます。片方でリソースを作成し、もう片方がそのリソースを「設定上存在しない」とみなして誤ってdestroyする。これが並走期間中に起きる典型的な事故です。

移行期のアーキテクチャ設計についてはTerraform実践トレーニング(terraform.linuxmaster.jp)でも扱っています。

並走期間中の主なリスクパターン

1. リソースの「二重所有」問題

Terraformで作成したVPCを、Pulumiのコードでも参照先として宣言してしまうケースです。Pulumiのpulumi stack outputでは既存リソースを参照できますが、プロジェクト設定を誤ると新規作成として扱い、同名リソースの競合エラーか意図しない新規リソースの作成が発生します。

# 二重所有が起きているときのエラー例(出力例・環境により異なります) error: Preview failed: aws:ec2/vpc:Vpc (main-vpc): error: VPC with CIDR 10.0.0.0/16 already exists Duplicate resource detected

2. terraform destroyが管轄外リソースを巻き込むリスク

同じAWSアカウント・リージョンで作業していると、Terraformのtfstateに登録されたリソースを一括削除するterraform destroyが、意図せずPulumiが作成したリソースに依存するリソースを削除してしまうことがあります。依存関係のあるSecurity GroupやIAM Roleが消えた場合、Pulumiで管理しているEC2がネットワーク接続を失うといった障害に直結します。

3. ドリフト検出の片側見逃し

terraform planはTerraformのstateを基準に差分を表示しますが、Pulumiが後から変更したリソースの状態はTerraform側には見えません。「planで変更なし」と表示されていても、Pulumi側でサブネットのCIDRが変更されていた、という状態になります。定期的なドリフト検出を両ツールで個別に実行しなければ、設定の乖離を見逃し続けます。

所有権を分ける基本設計(3ステップ)

1. IaC管轄境界をドキュメントで先に定義する

ツールの移行を始める前に、「どのリソース群をどのツールが管轄するか」を明文化します。一般的なパターンはレイヤー分割です。

・ネットワーク層(VPC・サブネット・ルートテーブル): Terraform管轄
・アプリケーション層(ECS・Lambda・RDS): Pulumi管轄(移行対象)
・セキュリティ層(IAM・Security Group): 移行完了まで両ツール共存(参照のみ・変更はTerraform)

この境界定義をdocs/iac-ownership.mdなどのファイルに落とし、チーム全員が参照できる状態にします。

2. terraform state rmとpulumi importでリソースを移管する

Pulumiの管轄に移すリソースは、TerraformのstateからはRDSを例として次の手順で除籍します。

# 手順1: Terraformのstateから対象リソースを取り除く # (実際のリソースは削除しない・stateの記録だけを除外する) terraform state list # 出力例(環境により異なります): # aws_db_instance.main # aws_db_subnet_group.main terraform state rm aws_db_instance.main terraform state rm aws_db_subnet_group.main # 手順2: 実際のリソースIDを取得する terraform show -json | python3 -c "import sys,json; [print(k,v['values']['id']) for k,v in json.load(sys.stdin)['values']['root_module']['resources'] if v['address'] == 'aws_db_instance.main']" 2>/dev/null || true # 手順3: PulumiにリソースIDを登録する(destroyせずインポート) pulumi import aws:rds/instance:Instance main db-prod-2024 # 出力例(環境により異なります): # Importing (dev): # + aws:rds/instance:Instance main imported # Resources: 1 imported

注意点: terraform state rmを実行する前にterraform state pull > state-backup.jsonでバックアップを取ってください。state操作は元に戻せないため、作業前のスナップショットは必須です。

3. prevent_destroyとignore_changesで誤操作の範囲を限定する

Terraform側に残っている「参照だけしたいリソース」には、誤ったdestroyを防ぐLifecycleルールを追加します。

# Pulumi管轄リソースをTerraformが参照だけする場合の保護設定 # (tfstateに残っている間の誤削除防止) resource "aws_security_group" "app" { name = "app-sg" # ... 設定省略 lifecycle { # destroyコマンドで消えないようにロック prevent_destroy = true # Pulumi側が変更してもTerraformが差分を検出して上書きしないよう除外 ignore_changes = [ingress, egress, tags] } }

ignore_changesに指定した属性はPulumi側が変更してもterraform planが差分として表示しなくなります。移管完了後はこのリソース定義ごとtfstateから削除します。

並走期間中の運用ルール

1. ディレクトリ構成でTerraform管轄とPulumi管轄を分離する

# 推奨ディレクトリ構成(例) infra/ terraform/ # Terraform管轄(ネットワーク層) modules/ environments/ dev/ prod/ README.md # 管轄範囲を明記する pulumi/ # Pulumi管轄(アプリケーション層) Pulumi.yaml Pulumi.dev.yaml src/ README.md # 管轄範囲を明記する docs/ iac-ownership.md # 境界定義ドキュメント

ルートのREADME.mdやiac-ownership.mdに「terraform配下はTerraform担当チームのみ変更可」「pulumi配下はPulumi担当チームのみ変更可」と明記し、PRレビューのルールとして組み込みます。

2. CIで交差アクセスを検出する

GitHub Actions等のCIでPRの差分ファイルをチェックし、Terraform配下からPulumi配下を直接参照しようとする変更を検出します。

# .github/workflows/iac-ownership-check.yml(抜粋) - name: Check IaC ownership boundary run: | # Terraform配下のファイル変更がPulumi配下のリソース名を参照していないか確認 changed_tf= if [ -n "" ]; then if grep -r "pulumi" 2>/dev/null | grep -v "#"; then echo "ERROR: Terraform code references Pulumi-managed resources directly" echo "Use data sources or remote_state to cross boundaries" exit 1 fi fi echo "Ownership boundary check: OK"

トラブルシュート|よくある競合パターンと対処

症状 原因 対処
terraform planでPulumi作成リソースの変更が出る 同一リソースがTerraformのstateにも記録されている terraform state rmでTerraformのstateから除籍する
pulumi upで「Resource already exists」エラー Terraform管轄リソースをPulumiが新規作成しようとしている pulumi importでインポートして所有権をPulumiに移す
terraform destroyで関係ないリソースが削除対象に入る Terraform stateに移管予定リソースが残っている 移管対象にprevent_destroy = trueを設定してからstate rm
どちらのツールが作ったかわからなくなった taggingルールが未統一 全リソースにmanaged_by = terraformまたはpulumiタグを付与するポリシーを設定する

まとめ

設計ポイント 具体的な方法
所有権の明示 ドキュメントとディレクトリ構成でTerraform・Pulumi管轄を分離
リソース移管 terraform state rmで除籍 → pulumi importで登録
誤操作防止 prevent_destroyとignore_changesで並走中のリソースを保護
CI検出 PRの差分ファイルから所有権境界の越境を自動検出
移管完了後 Terraform stateから除籍済みリソースの定義を削除してHCLをクリーンアップ
PulumiとTerraformの並走は「移行期の一時的な状態」と割り切り、移管対象リソースは境界定義ドキュメントを起点に計画的に移していくことが、state競合を起こさない最大のポイントです。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、
TerraformによるIaC設計の実践的な学習コースを用意しています。
コードレビューの視点から設計パターンまで、現場で使える知識を体系的にカバーしています。
>> Terraform実践トレーニングの詳細はこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録

運営

リナックスマスター.JP(代表 宮崎智広)

株式会社イーネットマーキュリーが運営するLinux教育サイトです。代表の宮崎智広は現役のLinuxサーバー管理者として20年以上の実務経験を持ち、累計3,100名以上のエンジニアを指導してきました。実践型のLinuxセミナーや無料マニュアルの配布を通じてLinux人材の育成に取り組んでいます。