🧑‍🤝‍🧑

[Terraform/AWS]複数のサブネットを一度に作る

2020/12/28に公開

はじめに

AWSでVPCを構築する際、パブリックサブネットとプライベートサブネットそれぞれ3AZずつの計6個(もしくは2AZずつの計4個)以上を作成するケースがあるかと思います。

今回、その個数分だけTerraformのresourceを記述するのではなく、まとめて作成してみたいと思います。

本記事ではTerraformの以下の機能を使います。

  • count
  • count.index
  • cidrsubnet関数
  • length関数

環境

  • Terraform 0.14.3

count

countを使うことで、指定した数だけresourceが作成されます。

subnet.tf
resource "aws_subnet" "public" {
  count = 3

  // 略
}

resource "aws_subnet" "private" {
  count = 3

  // 略
}

なお、countによって作成されたリソースは、0から始まる連番となります。

  # aws_subnet.public[0] will be created
  + resource "aws_subnet" "public" {
      + arn                             = (known after apply)
      // 略
    }

もし、連番0であるリソースの要素(例えばid)を参照する場合は、以下のように指定します。

nat_gateway.tf
resource "aws_nat_gateway" "example" {
  // 略
  subnet_id = aws_subnet.public[0].id
  // 略
}

count.index

countによって各サブネットが3個作成されますが、それぞれのアベイラビリティゾーンは別のものにする必要があります。

そのためにcount.indexを使うことにします。

まず、あらかじめアベイラビリティゾーン名を格納するlist型の変数availability_zonesを定義します。

valiables.tf
variable "availability_zones" {
  type    = list(string)
  default = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
}

その上で、list型である変数availability_zonesのインデックスを、count.indexで指定するようにします。

subnet.tf
resource "aws_subnet" "public" {
  count = 3

  availability_zone = var.availability_zones[count.index]

  // 略
}

resource "aws_subnet" "private" {
  count = 3

  availability_zone = var.availability_zones[count.index]

  // 略
}

これで、

  • 各サブネットの1個目は、アベイラビリティゾーンがap-northeast-1a
  • 各サブネットの2個目は、アベイラビリティゾーンがap-northeast-1c
  • 各サブネットの3個目は、アベイラビリティゾーンがap-northeast-1d

となります。

cidrsubnet関数とlength関数

最後に、各サブネットのCIDRがそれぞれ異なるようにします。

これにはcidrsubnet関数を使います。

cidrsubnet関数の使い方は以下の例を見たほうがわかりやすいと思います。

第一引数のCIDRを分割して返してくれます。

$ terrafform console
> cidrsubnet("172.31.0.0/16", 8, 0)
"172.31.0.0/24"

> cidrsubnet("172.31.0.0/16", 8, 1)
"172.31.1.0/24"

このcidrsubnet関数を使うと、サブネットの定義は以下になります。

subnet.tf
resource "aws_subnet" "public" {
  count = 3

  availability_zone = var.availability_zones[count.index]
  cidr_block        = cidrsubnet(aws_vpc.vpc.cidr_block, 8, count.index)

  // 略
}

resource "aws_subnet" "private" {
  count = 3

  availability_zone = var.availability_zones[count.index]
  cidr_block        = cidrsubnet(aws_vpc.vpc.cidr_block, 8, count.index + length(aws_subnet.public))

  // 略
}

なお、プライベートサブネットでは、パブリックサブネットとCIDRが重複しないよう、length関数を使用してcidrsubnet関数の第三引数を

  • count.index + length(aws_subnet.public))

としています。

これにより、

  • パブリックサブネットの3個目 : cidrsubnet({VPCのCIDR}, 8, 2)
  • プライベートサブネットの1個目 : cidrsubnet({VPCのCIDR}, 8, 3)

となり、CIDRが重複せず、連続するようになります。

終わりに

countの存在はもともと知ってはいたのですが、cidrsubnet関数は非常に便利ですね。

Terraformには他にも便利な関数があるので積極活用していきたいと思います。

参考

Discussion