シナリオ:単純な参照がワークフローを停止させるとき
大規模なインフラストラクチャのアップデートの最中だとしましょう。例えば、AWSプロバイダーをv4.0からv5.0に移行しているかもしれません。terraform planを実行し、クリーンな変更リストが表示されることを期待します。しかし、代わりにターミナルには赤色のテキストの壁が表示されます。
Error: Unsupported attribute
on main.tf line 42, in resource "aws_instance" "web":
42: subnet_id = data.aws_subnet.selected.id_name
This object does not have an attribute named "id_name".
このエラーは、プロバイダーのスキーマに存在しないプロパティを参照したときに発生します。ネストされたブロックでよく起こります。メッセージ自体は明快ですが、複雑なモジュールの中で欠落しているリンクを正確に特定するのは、干し草の山から針を探すような気分になるかもしれません。
なぜTerraformはこのエラーをスローするのか
Infrastructure as Code(コードとしてのインフラ)は厳格です。参照が失敗する主な理由は以下の通りです:
- 単純なタイポ(入力ミス):
dns_nameと書いたが、プロバイダーはpublic_dnsを要求している場合。 - プロバイダーの破壊的変更: メジャーアップデートでは属性名が変更されることがよくあります。例えば、AzureRMプロバイダーはバージョン間で
nameフィールドをresource_idに変更する場合があります。 - コレクションの罠: これが最も一般的な原因です。
countやfor_eachを使用すると、Terraformはそのリソースを単一のオブジェクトではなく、リストまたはマップとして扱ります。 - 隠れたモジュール出力:
module.vpc.vpc_idを読み取ろうとしていますが、VPCモジュールのoutputs.tfでその値がエクスポートされていない場合。
60秒でできる修正:Terraform Console
推測するのはやめましょう。terraform consoleを使用して、ステートエンジンが実際に何を見ているかを確認します。これは、失敗したプランをデバッグする最も効率的な方法です。
- ターミナルでプロジェクトのルートに移動します。
terraform consoleと入力して環境を起動します。data.aws_subnet.selectedなどのリソースアドレスを入力し、Enterキーを押します。
コンソールには、オブジェクトの完全なJSON形式の構造が出力されます。通常、属性名が異なっているか、移動し忘れたネストされたブロックの中に埋もれていることがわかります。
ステップバイステップの解決策
1. スキーマの不一致の修正
Terraform Registryで属性名を確認してください。最近.terraform.lock.hclを更新した場合は、プロバイダーの変更がコード破損の原因である可能性が高いです。
# 誤り
output "instance_ip" {
value = aws_instance.web.ip_address
}
# 正しい
output "instance_ip" {
value = aws_instance.web.public_ip
}
2. インデックス作成の問題の解決(CountとFor_Each)
count = 1でリソースを定義しても、それはリストになります。Terraformはインデックスを期待するため、aws_instance.web.idに直接アクセスすることはできません。スプラット演算子([*])を使用してすべてのIDを取得するか、特定のインデックスを指定してください。
# 誤り: 'server'は2つのアイテムを持つリストであるため失敗します
resource "aws_instance" "server" {
count = 2
}
output "ids" {
value = aws_instance.server.id
}
# 正しい: リスト全体にスプラット構文を使用する
output "all_ids" {
value = aws_instance.server[*].id
}
# 正しい: 特定の最初のインスタンスをターゲットにする
output "first_id" {
value = aws_instance.server[0].id
}
3. モジュール変数のエクスポート
モジュールはデフォルトでブラックボックスです。親の設定からmodule.network.vpc_idが見えない場合は、そのモジュールディレクトリ内のoutputs.tfファイルを確認してください。値を明示的に公開する必要があります。
# /modules/network/outputs.tf 内
output "vpc_id" {
description = "VPCのID"
value = aws_vpc.main.id
}
プロのヒント:オプションのフィールドには try() を使用する
空の可能性があるtagsマップのように、特定の環境でのみ存在する属性もあります。try()関数を使用してフォールバック値を定義し、プランのクラッシュを防ぎましょう。
# 'Name'タグがない場合のデフォルト値を指定する
locals {
instance_name = try(aws_instance.web.tags["Name"], "unnamed-resource")
}
修正を確認する方法
エラーが完全に解消されたことを確認するために、次の3つのステップに従ってください:
terraform validateを実行します。これにより、クラウドに接続せずに構文エラーや属性エラーを検出できます。terraform planを実行します。赤いテキストが表示されずにプランが成功すれば、マッピングが正しいことが確認できます。terraform consoleで再テストします。失敗していた特定の式を評価し、期待通りの文字列または数値が返されることを確認します。

