LoginSignup
4
5

More than 3 years have passed since last update.

[Terraform]同一リソース内で複数作成する場合、countよりfor_eachを使う

Posted at

Terraform 0.12以前はcount-functioncidrsubnet-functionを使用してネットワークを作成していましたが、ネットワークに変更が入るときにリソースが再作成されてしまう問題がありました。また、可読性も落ちます。HCL2ではfor_eachを使うことで可読性を上げ、既存リソースに影響が出ないようにリファクタリングできます。

count

リソースのcountパラメーターを使用すると、構成を単純化し、単純に数値を増加させることによってリソースを拡張することができます。

aws_instance.tf
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
aws_subnet.tf
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"
  }
}
variables.tf
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を使用すると、定義されている要素の数だけループするので、配列に配慮せずに変更が可能になり、可読性も上がります。

aws_subnet.tf
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"
  }
}
variables.tf
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"
    }
  }
}
4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5