【Terraform】countで作成したリソースの参照はインデックスを指定しないとダメみたい
Terraform で count を使用して Validate したらエラーになりました。
文法的なエラーになったので、原因調査 ⇒ 修正の過程をまとめていきます
結論
タイトル通りですが、
Terraform で count を使用して作成したリソースを参照するにはインデックスを指定しないとダメ
みたいです
count とは?
count とは数値型で、指定した数だけリソースを作成します。
例えば、↓ のように count を使用すると EC2 を2つ作成します
resource "aws_instance" "server" {
count = 2
...
}
複数同じものを作成するときに便利ですよね~
でも、これもうひとつ素晴らしい使い方があります
リソースを作成するかのフラグとしても使えるんです!!
例えば ↓ のように変数を使用して
// EC2をいくつ作るかをしていする変数
variable "count_ec2" {
default = 0
}
resource "aws_instance" "server" {
count = var.count_ec2
...
}
作成しない →count_ec2 は0
作成する →count_ec2 は作成したい個数
とすることで簡単に作成するしないを制御することができます
やりたいこと
- 2つの AZ で同じような Subnet などを作成するので module 化する
- ただし、片方の AZ のみ NAT Gateway を作成する
これを満たすように module を作ろうと思ったら、count を使ってみるかとなりました
作った module
ディレクトリ構成
./modules/subnet
├── README.md
├── main.tf
├── outputs.tf
└── variables.tf
コード
NAT Gateway に関したところだけ切り出します
・main.tf
# NATゲートウェイ
resource "aws_nat_gateway" "main" {
# リソースを作成するか
# 0:作成しない、1:作成する
count = var.count_nat_gateway
# EIPの指定
allocation_id = aws_eip.nat_gateway.id
# パブリックサブネットを指定
subnet_id = aws_subnet.public.id
tags = {
Name = "${var.prefix}-nat_gateway-${var.az}"
}
}
# NATゲートウェイ用EIP
resource "aws_eip" "nat_gateway" {
count = var.count_nat_gateway
domain = "vpc"
tags = {
Name = "${var.prefix}-eip-nat_gateway-${var.az}"
}
}
# Route
# プライベートサブネット → NATゲートウェイへの通信を許可
resource "aws_route" "private" {
count = var.count_nat_gateway
route_table_id = aws_route_table.private.id
nat_gateway_id = aws_nat_gateway.main.id
destination_cidr_block = "0.0.0.0/0"
}
・variables.tf
# NAT Gatewayをいくつ作るか
variable "count_nat_gateway" {
default = 0
}
# Prefix
variable "prefix" {
type = string
}
・README.md と outputs.tf
本記事の内容に関係ないため省略します
エラー内容
先ほどのコードで terraform validate をすると、エラーになりました
│ Error: Missing resource instance key
│
│ on ../../modules/subnet/main.tf line 92, in resource "aws_nat_gateway" "main":
│ 92: allocation_id = aws_eip.nat_gateway.id
│
│ Because aws_eip.nat_gateway has "count" set, its attributes must be
│ accessed on specific instances.
│
│ For example, to correlate with indices of a referring resource, use:
│ aws_eip.nat_gateway[count.index]
╵
Error: Terraform exited with code 1.
Error: Process completed with exit code 1.
EIP で count を使用しているため、
aws_nat_gateway ブロック内で EIP を指定する際にインデックスが必要そう。
ちゃんと調べてみましょう!
原因調査
公式ドキュメントの count のページに答えがありました
When
count
is set, Terraform distinguishes between the block itself and the multiple resource or module instances associated with it. Instances are identified by an index number, starting with0
.
<TYPE>.<NAME>
ormodule.<NAME>
(for example,aws_instance.server
) refers to the resource block.<TYPE>.<NAME>[<INDEX>]
ormodule.<NAME>[<INDEX>]
(for example,aws_instance.server[0]
,aws_instance.server[1]
, etc.) refers to individual instances.
DeepL さんに翻訳してもらいました
count を設定すると、Terraform はブロックそのものと、それに関連する複数のリソースやモジュールのインスタンスを区別する。インスタンスは 0 から始まるインデックス番号で識別される。
・<TYPE>.<NAME>または module.<NAME>(例えば aws_instance.server)はリソースブロックを指します。 ・<TYPE>.<NAME>[<INDEX>]または module.<NAME>[<INDEX>](例えば aws_instance.server[0]、aws_instance.server[1]など)は個々のインスタンスを指します。
count を使用して作成したリソースについて、
個々のインスタンス(作成したもの?)を指定するにはインデックスが必要ということ。
修正して再度確認
原因わかったので、インデックスを指定します
・main.tf
# NATゲートウェイ
resource "aws_nat_gateway" "main" {
# リソースを作成するか
# 0:作成しない、1:作成する
count = var.count_nat_gateway
# EIPの指定
+ allocation_id = aws_eip.nat_gateway[0].id
# パブリックサブネットを指定
subnet_id = aws_subnet.public.id
tags = {
Name = "${var.prefix}-nat_gateway-${var.az}"
}
}
# NATゲートウェイ用EIP
resource "aws_eip" "nat_gateway" {
count = var.count_nat_gateway
domain = "vpc"
tags = {
Name = "${var.prefix}-eip-nat_gateway-${var.az}"
}
}
# Route
# プライベートサブネット → NATゲートウェイへの通信を許可
resource "aws_route" "private" {
count = var.count_nat_gateway
route_table_id = aws_route_table.private.id
+ nat_gateway_id = aws_nat_gateway.main[0].id
destination_cidr_block = "0.0.0.0/0"
}
修正したら terraform validate に通り、apply も無事終わりました!!
最後に
count を使用したときにエラーに立ち向かいました。
やはり公式ドキュメントは偉大ですね。
参考
Discussion