Search code examples
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:

  • Use data "aws_subnet" "all_app_subnets" {...}, filter by name, get all the subnets that match and use them as a list. But aws_subnet cannot return a list;
  • Use data "aws_availability_zones" {...} to find all the zones. But I still have the problem of assigning the correct subnet;
  • Use data "aws_subnet_ids" {...} which looks like the best option. But apparently it doesn't have a filter option to match the networks namel
  • Pass the subnets IDs as list of strings to the module. But I don't want to hard code the IDs, it's not automation;
  • Hard code the subnets as data "aws_subnet" "app_subnet_1" {...}, data "aws_subnet" "app_subnet_2" {...} but then I have to use separate sets of variables for each subnet which I don't like;
  • Get information for each subnet like in the point above but then create a map to access it as a list. But it's not possibile to use interpolation in variables definition;
  • Not using modules and hard-code each instance for each environment. Mmmm... really?

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)
    
      ...
    }