pog0
pog0

Reputation: 13

Creating multiple subnets in order per availability zone with Terraform

New to Terraform and trying to create the following VPC from Adrian Cantril's class using the DRY method.

VPC Diagram

I can get the first 4 subnets created but when I try to repeat it, it duplicates it per AZ giving me an error.

I have tried a few other things that created 1 subnet per AZ, e.g. 10.16.0.0/20 in AZ A, 10.16.16.0 /20 in AZ B, etc..

Below is a snippet of the code I am using.

variable "vpc_cidr" {
  type    = string
  default = "10.16.0.0/16"
}

resource "aws_subnet" "private_subnets-az-a" {
  count             = 4
  vpc_id            = aws_vpc.vpc.id
  cidr_block        = cidrsubnet(var.vpc_cidr, 4, count.index)
  availability_zone = data.aws_availability_zones.available.names[0]
}

resource "aws_subnet" "private_subnets-az-b" {
  count             = 4
  vpc_id            = aws_vpc.vpc.id
  cidr_block        = cidrsubnet(var.vpc_cidr, 4, count.index)
  availability_zone = data.aws_availability_zones.available.names[1]

Upvotes: 0

Views: 2348

Answers (2)

Robert de Bock
Robert de Bock

Reputation: 1

I think there is a simpler way to achieve this:

# Loop up Availability Zones.
data "aws_availability_zones" "available" {}

# Create subnets.
resource "aws_subnet" "default" {
  count             = 3
  vpc_id            = aws_vpc.default.id
  cidr_block        = "10.0.${count.index}.0/24"
  availability_zone  = data.aws_availability_zones.available.names[count.index]
}

Upvotes: 0

Anton
Anton

Reputation: 1966

This should be pretty DRY:

locals {
  region  = "us-east-1"
  subnets = {
    for i, v in setproduct(["a", "b", "c"], ["reserved", "db", "app", "web"]) :
    "${local.region}${v[0]}-${v[1]}" =>
    {
      az   = "${local.region}${v[0]}"
      cidr = cidrsubnet("10.16.0.0/16", 4, i)
    }
  }
}

resource "aws_subnet" "this" {
  for_each          = local.subnets

  vpc_id            = aws_vpc.vpc.id
  cidr_block        = each.value.cidr
  availability_zone = each.value.az
}

This will create 12 subnets as per the diagram.

locals.subnets looks like this:

subnets = {
  "us-east-1a-reserved" = {
    "az" = "us-east-1a"
    "cidr" = "10.16.0.0/20"
  }
  "us-east-1a-db" = {
    "az" = "us-east-1a"
    "cidr" = "10.16.16.0/20"
  }
  "us-east-1a-app" = {
    "az" = "us-east-1a"
    "cidr" = "10.16.32.0/20"
  }
  "us-east-1a-web" = {
    "az" = "us-east-1a"
    "cidr" = "10.16.48.0/20"
  }
  "us-east-1b-reserved" = {
    "az" = "us-east-1b"
    "cidr" = "10.16.64.0/20"
  }
  // ... and so on
}

This for_each approach is more usable than the count variants because you can access the created subnets as follows: aws_subnet.this["us-east-1a-reserved"].arn as opposed to aws_subnet.this[3].arn.

See setproduct and for expressions to understand what's going on in locals.subnets.

On a related note, it's a good idea to try to create a VPC and subnets from scratch when you are learning, but if you go to production, I'd recommend using this Terraform VPC module - https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest.

Upvotes: 3

Related Questions