ENECHANGE Developer Blog

ENECHANGE開発者ブログ

[Terraform] countで作成した設定ファイルをfor_eachでリファクタリングする

こんにちは。リモートワークに伴う運動不足解消のため、日々、Z戦士として走り込んでいるCTO室のkazです。

概要

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

count

www.terraform.io

リソースの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

www.terraform.io

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

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

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

www.terraform.io

for_eachでmapを使用すると、定義されている要素の数だけループするので、配列に配慮せずに変更が可能になり、可読性も上がります。

aws_subnet

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

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"
    }
  }
}


ENECHANGEではエネルギーの未来を作る仲間を募集しています。 ぜひエントリーを!!!!

enechange.co.jp