なぜこのエラーが発生するのか
terraform plan は完璧に通るのに、apply で失敗することほど混乱することはありません。plan 中には属性が null だったのに、apply フェーズで i-0123456789abcdef0 のような特定の値になったというメッセージが表示されることがあります。これは、Terraform Core とプロバイダー間の規約(コントラクト)が崩れたために発生します。
Terraform はプロバイダーが正確であることを期待しています。もしプロバイダーが Terraform に対して「ID がどうなるかまだわからない」と伝える場合、その属性を (known after apply) とマークしなければなりません。プロバイダーが誤って属性を null になると宣言したにもかかわらず、リソース作成後にクラウド API が実際の値を返した場合、Terraform はプロセスを停止します。これは、ステートファイルに破損したデータが保存されるのを防ぐためです。
主な原因
通常、この問題は以下の 3 つのシナリオのいずれかに集約されます:
- プロバイダーのロジックの不備: これが最も頻繁な原因です。例えば、AWS プロバイダー v3.x では、API が予期せずデフォルトタグを追加した場合に、
tags_allが整合性エラーを引き起こす既知の問題がありました。 - 隠れたステートのドリフト: リソースがクラウド環境には存在するが、ステートで追跡されていない場合があります。Terraform がそれを作成しようとすると、API は既存の ID を返し、plan の内容と矛盾が生じます。
- API の進化: AWS や Azure などのクラウドベンダーは、頻繁に API レスポンスを更新します。古いプロバイダーバージョン(例:AWS プロバイダー v4.0)を新しい API 挙動に対して使用している場合、プロバイダーが新しいメタデータの処理方法を認識できないことがあります。
解決方法
1. リフレッシュによるステートの同期
まず、ローカルのステートを実際の状況と一致させることから始めます。これにより、ウェブコンソールでの手動変更や、前回の実行の中断によって生じた不整合が修正されることがよくあります。最新の Terraform バージョンでは、インフラを変更せずに変更点を確認できる refresh-only プランニングモードを使用してください。
# まずドリフトを確認する
terraform plan -refresh-only
# ドリフトが検出された場合、ステートを更新する
terraform apply -refresh-only
2. プロバイダーバージョンの調整
エラーが既知のバグである場合、プロバイダーのアップグレードが最善の策です。特定のソースで他のユーザーが同様の挙動を報告していないか、AWS Provider GitHub Issues を確認してください。required_providers 内のバージョン制約を更新します。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.10.0" # 特定の安定版リリースを指定する
}
}
}
バージョン変更後、terraform init -upgrade を実行します。アップグレード直後にエラーが発生した場合は、安定性を取り戻すために 1 つ前のマイナーバージョンにロールバックしてみてください。
3. 問題のあるリソースの特定
大規模なデプロイではデバッグが困難です。エラーをスローしているリソースのみをターゲットにしてスコープを絞り込みます。これにより複雑な依存関係グラフをバイパスし、問題がその特定のコードブロックに限定されているかどうかを確認できます。
terraform apply -target=aws_instance.web_server
4. ステートの手動操作
Terraform が特定の ID で完全に行き詰まった場合、ステートファイルに「手術」を施す必要があるかもしれません。リソースが実際にクラウドコンソールに存在する場合は、ステートから削除して再インポートします。これにより、Terraform は API から直接現在の属性を読み込むよう強制されます。
# ステートから参照を削除(安全:VMは削除されません)
terraform state rm aws_instance.web_server
# 物理IDを使用して実際のリソースを再インポートする
terraform import aws_instance.web_server i-0123456789abcdef0
検証と予防
修正が恒久的であることを確認するために、terraform plan を実行します。「No changes」というメッセージが表示されるはずです。機密性の高いインフラを管理している場合は、チーム内でのマージ中にローカル設定ファイルが変更されたり破損したりしていないか確認してください。私はよく、ToolCraft の Hash Generator を使用して、ローカルステートのバックアップとリモートバージョンの SHA-256 チェックサムを比較します。これは、生の JSON ステートをサードパーティのサーバーに公開することなく、ファイルの整合性を確認する迅速な方法です。
長期的な安定性のために、常に依存関係ロックファイル(.terraform.lock.hcl)を使用してください。これにより、CI/CD パイプラインがバグのあるプロバイダーバージョンを自動的に取得し、本番環境の apply を突然壊してしまうのを防ぐことができます。

