0
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

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

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"
    }
  }
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
0
Help us understand the problem. What are the problem?