Loop a resource with for_each inside

I’m doing tests with terraform and I didn’t found a solution on internet for this situation.

I have 4 environments (default, testing, prod, high). Each environment has AZ requirements… default has 1 AZ, testing 1 AZ, prod 2 AZ and high use all AZ in the region

and for each environment I have to create X instances per AZ. for default and testing 1 instance, for prod 2 instances, for high 3 instances.

I setup local vars:

data "aws_availability_zones" "available" {}
locals {
  env="${terraform.workspace}"
  #number of instances per AZ
  counts = {
    "default"     = 1
    "testing"     = 1
    "production"  = 1
    #high demand
    "high"        = 3
  }
 #number of subnets
  subnet_public = {
    "default"     = 1
    "testing"     = 1
    "production"  = 2
    #use all AZ disponible to create subnets
    "high"        = length(data.aws_availability_zones.available.names)
  }
  instance_count      = lookup(local.counts,local.env)
  instance_type = "t2.micro"
}

Now I’m trying create X instances per AZ

    #create X instances per public subnet
    for(i = 0; i < local.instance_count; i++) {      
        resource "aws_instance" "public_rproxy" {
            for_each                    = aws_subnet.public
            ami                             = data.aws_ami.amazon-linux-2.id
            associate_public_ip_address = true
            instance_type               = local.instance_type
            key_name                    = "wordpress-environment-key"
            vpc_security_group_ids      = [ aws_security_group.SG-FrontEnd ]
            subnet_id                   = each.value.id
            user_data                   =  file("deploy_nginx_rproxy.sh")

        tags = {
          Name        = "Public-Proxy-Server-${local.env}"
          Environment = "${local.env}"
          Application = "FrontEnd-NGINX-RProxy"
        }
      }
    }

but terraform shows error in the for statement
49: for(i = 0; i < local.instance_count; i++) {

The ";" character is not valid. Use newlines to separate arguments and blocks,

and commas to separate items in collection values.

How I can create X instances in each AZ?

thanks

Terraform is not C/C++. You can’t write for-loops that way. Please consult the docs at

In your case you probably don’t even need a for-loop, you can just use count = local.instance_count in the resource block.

I found the example using this for on the internet.

But if I use local.instance_count how to create X instances in Y AZ?

I need create a number of instances per AZ… and the number of AZ is based on the environment.

for example if I use count how to define the subnets? the local.instance_count is the number of instances inside one AZ, but if I use the example below I will create a number of instances but I can’t find a logic way to determine the AZ

resource "aws_instance" "public_rproxy" {
            count                    = local.instance_count
            ami                             = data.aws_ami.amazon-linux-2.id
            associate_public_ip_address = true
            instance_type               = local.instance_type
            key_name                    = "wordpress-environment-key"
            vpc_security_group_ids      = [ aws_security_group.SG-FrontEnd ]
            subnet_id                   = ????
            user_data                   =  file("deploy_nginx_rproxy.sh")

        tags = {
          Name        = "Public-Proxy-Server-${local.env}"
          Environment = "${local.env}"
          Application = "FrontEnd-NGINX-RProxy"
        }
      }

and to use for_each I will create only 1 instance per subnet

resource “aws_instance” “public_rproxy” {
for_each = aws_subnet.public
ami = data.aws_ami.amazon-linux-2.id
associate_public_ip_address = true
instance_type = local.instance_type
key_name = “wordpress-environment-key”
vpc_security_group_ids = [ aws_security_group.SG-FrontEnd ]
subnet_id = each.value.id
user_data = file(“deploy_nginx_rproxy.sh”)

    tags = {
      Name        = "Public-Proxy-Server-${local.env}"
      Environment = "${local.env}"
      Application = "FrontEnd-NGINX-RProxy"
    }
  }

And the idea is create a number of instances for each AZ

Are you using subnet_id as a proxy for the AZ? Your resource declarations are specifying the AZ at all.

Yes, I forgot… I create one subnet per AZ and after I get the subnets:

data "aws_subnet_ids" "public_ids" {
          vpc_id = aws_vpc.principal.id
          tags = {
            Type = "Public"
            Environment = local.env
          }
        }

and in the resource instance

resource "aws_instance" "public_web_server" {
    for_each                    = data.aws_subnet_ids.public_ids.ids
     ami                         = data.aws_ami.amazon-linux-2.id
     associate_public_ip_address = true
     instance_type               = local.instance_type
     key_name                    = "wordpress-environment-key"
     subnet_id                   = each.value
     #vpc_security_group_ids      = [ aws_security_group.SG-FrontEnd ]
     #user_data                   =  file("deploy_nginx_proxy.sh")
     tags = {
       Name        = "Public-Proxy-Server-${local.env}"
       Environment = "${local.env}"
       Application = "Wordpress"
     }
}

Of course, I don’t know if it’s a good way to deploy… I’m testing the options and trying mix options and possibilities to understand what is possible to do.

You are basically trying to do nested loops… I’m not familiar with how to do that, but hopefully someone else will be able to assist.

Thank you @kpfleming for your help. With your tip "nested loop"I found a solution.
I created a total_instance variable (multiplication of number of instances with subnets/AZ and the total of subnets/az)
total_instances = local.num_subnet_public * local.instance_count

I use count as total_instances and use the operator % to get the division remainder count.index by the total of subnets/AZ and works.

resource "aws_instance" "public_web_server" {
    count                       = local.total_instances
     ami                         = data.aws_ami.amazon-linux-2.id
     associate_public_ip_address = true
     instance_type               = local.instance_type
     key_name                    = "wordpress-environment-key"
     subnet_id                   = aws_subnet.public[count.index % local.num_subnet_public].id
     #vpc_security_group_ids      = [ aws_security_group.SG-FrontEnd ]
     #user_data                   =  file("deploy_nginx_proxy.sh")
     tags = {
       Name        = "Public-Proxy-Server-${local.env}"
       Environment = "${local.env}"
       Application = "Wordpress"
     }
} 

Now I will make some tests to confirm all workspaces will work with this solution.

Thank you :slight_smile:

1 Like