Terraformでcountを使用してValidateしたらエラーになりました。
文法的なエラーになったので、原因調査⇒修正の過程をまとめていきます
結論
タイトル通りですが、
Terraformでcountを使用して作成したリソースを参照するにはインデックスを指定しないとダメ
みたいです
countとは?
countとは数値型で、指定した数だけリソースを作成します。
例えば、↓のようにcountを使用するとEC2を2つ作成します
1 2 3 4 5 6 |
resource "aws_instance" "server" { count = 2 ... } |
複数同じものを作成するときに便利ですよね~
でも、これもうひとつ素晴らしい使い方があります
リソースを作成するかのフラグとしても使えるんです!!
例えば↓のように変数を使用して
1 2 3 4 5 6 7 8 9 10 11 |
// EC2をいくつ作るかをしていする変数 variable "count_ec2" { default = 0 } resource "aws_instance" "server" { count = var.count_ec2 ... } |
作成しない→count_ec2 は0
作成する →count_ec2 は作成したい個数
とすることで簡単に作成するしないを制御することができます
やりたいこと
このインフラを構築するTerraformのコードを↓の要件に沿って作成
- 2つのAZで同じようなSubnetなどを作成するのでmodule化する
- ただし、片方のAZのみNAT Gatewayを作成する
これを満たすようにmoduleを作ろうと思ったら、countを使ってみるかとなった
作ったmodule
ディレクトリ構成
./modules/subnet
├── README.md
├── main.tf
├── outputs.tf
└── variables.tf
コード
NAT Gatewayに関したところだけ切り出します
・main.tf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# 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
1 2 3 4 5 6 7 8 9 |
# NAT Gatewayをいくつ作るか variable "count_nat_gateway" { default = 0 } # Prefix variable "prefix" { type = string } |
・README.mdとoutputs.tf
本記事の内容に関係ないため省略します
エラー内容
先ほどのコードでterraform validateをすると、エラーになりました
1 2 3 4 5 6 7 8 9 10 11 12 13 |
│ 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# 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を使用したときにエラーに立ち向かいました。
やはり公式ドキュメントは偉大ですね。
参考
コメント