amazon-web-servicesamazon-ec2terraformavailability-zone

Multiple availability zones with terraform on AWS


The VPC I'm working on has 3 logical tiers: Web, App and DB. For each tier there is one subnet in each availability zone. Total of 6 subnets in the region I'm using.

I'm trying to create EC2 instances using a module and the count parameter but I don't know how to tell terraform to use the two subnets of the App tier. An additional constraint I have is to use static IP addresses (or a way to have a deterministic private name)

I'm playing around with the resource

resource "aws_instance" "app_server" {
  ...
  count = "${var.app_servers_count}"

  # Not all at the same time, though!
  availability_zone = ...
  subnet_id = ...
  private_ip = ...
}

Things I've tried/thought so far:

I really ran out of ideas. It seems that nobody has to deploy instances in specific subnetworks and keep a good degree of abstration. I see only examples where subnetworks are not specified or where people just use default values for everything. Is this really something so unusual?

Thanks in advance to everyone.


Solution

  • At the end I figured out how to do it, using data "aws_subnet_ids" {...} and more importantly understanding that terraform creates lists out of resources when using count:

    variable "target_vpc" {}
    variable "app_server_count" {}
    variable "app_server_ip_start" {}
    
    # Discover VPC
    data "aws_vpc" "target_vpc" {
      filter = {
        name = "tag:Name"
        values = [var.target_vpc]
      }
    }
    
    # Discover subnet IDs. This requires the subnetworks to be tagged with Tier = "AppTier"
    data "aws_subnet_ids" "app_tier_ids" {
      vpc_id = data.aws_vpc.target_vpc.id
      tags {
        Tier = "AppTier"
      }
    }
    
    # Discover subnets and create a list, one for each found ID
    data "aws_subnet" "app_tier" {
      count = length(data.aws_subnet_ids.app_tier_ids.ids)
      id = data.aws_subnet_ids.app_tier_ids.ids[count.index]
    }
    
    resource "aws_instance" "app_server" {
      ...
    
      # Create N instances
      count = var.app_server_count
    
      # Use the "count.index" subnet
      subnet_id = data.aws_subnet_ids.app_tier_ids.ids[count.index]
    
      # Create an IP address using the CIDR of the subnet
      private_ip = cidrhost(element(data.aws_subnet.app_tier.*.cidr_block, count.index), var.app_server_ip_start + count.index)
    
      ...
    }