Terraform 0.12以前はcount-functionとcidrsubnet-functionを使用してネットワークを作成していましたが、ネットワークに変更が入るときにリソースが再作成されてしまう問題がありました。また、可読性も落ちます。HCL2ではfor_eachを使うことで可読性を上げ、既存リソースに影響が出ないようにリファクタリングできます。
count
リソースのcountパラメーターを使用すると、構成を単純化し、単純に数値を増加させることによってリソースを拡張することができます。
resource "aws_instance" "web" {
instance_type = "t3.small"
ami = lookup(var.aws_amis, var.aws_region)
# This will create 4 instances
count = 4
}
cidrsubnet
3つの引数を使用してネットワークを計算してくれます。
cidrsubnet(prefix, newbits, netnum)
- prefixはCIDR表記で指定
- newbitsはプレフィックスを拡張する追加ビットの数
- netnumは、2進数で表現できる整数
> cidrsubnet("172.20.0.0/16", 3, 2)
172.20.64.0/19
> cidrsubnet("172.20.0.0/24", 4, 15)
172.20.0.240/28
cidrsubnet("172.20.0.0/16", 3, x)を例にすると、netnumをインクリメントしていくと/16の上位3bitにインクリメントしたビットが割り当てられるので、
下記のようなネットワークが作成されます。
172.20.0.0 10101100.00010100. 00000000.00000000
172.20.32.0 10101100.00010100.001 00000.00000000
172.20.64.0 10101100.00010100.010 00000.00000000
172.20.96.0 10101100.00010100.011 00000.00000000
172.20.128.0 10101100.00010100.100 00000.00000000
172.20.160.0 10101100.00010100.101 00000.00000000
172.20.192.0 10101100.00010100.110 00000.00000000
172.20.224.0 10101100.00010100.111 00000.00000000
上記を踏まえ、4つのネットワークを作成する設定は下記になります。
- region = ap-northeast-1
- availability zone = apne1-az4,apne1-az1
resource "aws_subnet" "environment_example_subnet" {
count = 4
vpc_id = data.aws_vpc.environment_example.id
availability_zone = var.environment_example_subnet_availability_zones[count.index % 2]
cidr_block = cidrsubnet(data.aws_vpc.environment_example.cidr_block, 3, count.index)
tags = {
Name = var.environment_example_subnet_names[count.index]
Service = "environment_example"
Description = "Managed by Terraform"
}
}
variable "environment_example_subnet_availability_zones" {
type = list
default = [
"ap-northeast-1a",
"ap-northeast-1c",
]
}
問題点
この設定だと、countやvariableの値を変更すると、aws_subnet.environment_example_subnet[x]
の各配列が再作成されて既存環境に影響が出てしまいます。
解決策
for_each
for_eachでmapを使用すると、定義されている要素の数だけループするので、配列に配慮せずに変更が可能になり、可読性も上がります。
resource "aws_subnet" "environment_example_subnet" {
vpc_id = aws_vpc.environment_example.id
availability_zone = each.value.zone
for_each = var.environment_example_subnets
cidr_block = each.value.cidr
map_public_ip_on_launch = each.value.launch
tags = {
Name = each.value.name
Service = "environment_example"
Description = "Managed by Terraform"
}
}
variable "environment_example_subnets" {
type = map
default = {
public-1a = {
cidr = "172.20.0.0/19"
zone = "ap-northeast-1a"
launch = "true"
name = "environment-example-public-a"
}
public-1c = {
cidr = "172.20.32.0/19"
zone = "ap-northeast-1c"
launch = "true"
name = "environment-example-public-c"
}
private-1a = {
cidr = "172.20.64.0/19"
zone = "ap-northeast-1a"
launch = "false"
name = "environment-example-private-a"
}
private-1c = {
cidr = "172.20.128.0/19"
zone = "ap-northeast-1c"
launch = "false"
name = "environment-example-private-c"
}
}
}