首页 > 解决方案 > 如何使用 terraform 创建具有多个子网 ID 的多个实例?

问题描述

我有 2 个服务 test1、test2 并且对于每个服务我必须创建 6 个 vm。这 6 个 vm 应该放置在 3 个子网 id 中,这些子网 id 在同一区域的 3 个不同区域中创建

在此服务中,test1 将在私有子网中,而 test2 将在公共子网中。所以我必须在创建 ec2 实例时传递正确的子网 ID

根模块:

provider "aws" {
  region = var.region
}

module "ecom-vpc" {
  source = "./modules/vpc"
}

module "ecom-public-subnet" {
  source = "./modules/subnets/public"
  vpc-id = module.ecom-vpc.vpc-id
}

module "ecom-private-subnet" {
  source = "./modules/subnets/private"
  vpc-id = module.ecom-vpc.vpc-id
}

module "ecom-instances-sg" {
  source = "./modules/sg"
  vpc-id = module.ecom-vpc.vpc-id
}

module "ecom-vm-instances" {
  source = "./modules/vm"
  priv-subnet-ids = module.ecom-private-subnet.ecom_private_subnets
  pub-subnet-ids = module.ecom-public-subnet.ecom_public_subnets
  instances-sg = module.ecom-instances-sg.ecom-inst-sg
}

从子模块 - vpc、子网、ec2

variable "service-names" {
  type    = list(any)
  default = ["ecom-app-TEST1","ecom-app-TEST2"]

}

variable "availability_zones" {
  type = map
  default = {
    ap-south-1a = {
      private_subnet = "10.0.1.0/24"
      public_subnet  = "10.0.4.0/24"
    }
    ap-south-1b = {
      private_subnet = "10.0.2.0/24"
      public_subnet  = "10.0.5.0/24"
    }
    ap-south-1c = {
      private_subnet = "10.0.3.0/24"
      public_subnet  = "10.0.6.0/24"
    }
      }
  }

resource "aws_vpc" "ecom-vpc" {
  cidr_block = var.ecom-cidr
}

output "vpc-id" {
  value = aws_vpc.ecom-vpc.id
}

resource "aws_subnet" "ecom-private" {
  for_each = var.availability_zones
  vpc_id                  = var.vpc-id
  cidr_block              = each.value.private_subnet
  availability_zone       = each.key
  map_public_ip_on_launch = false
  tags = {
    Name = "${split("-", each.key)[2]}"
    Subnet_Type = "private"
  }
}

output "ecom_private_subnets" {
  value = aws_subnet.ecom-private
}

resource "aws_subnet" "ecom-public" {
  for_each = var.availability_zones
  vpc_id                  = var.vpc-id
  cidr_block              = each.value.public_subnet
  availability_zone       = each.key
  map_public_ip_on_launch = true
  tags = {
    Name = "${split("-", each.key)[2]}"
    Subnet_Type = "public"
  }
  depends_on = [aws_internet_gateway.igw
  ]
}

  
output "ecom_public_subnets" {
  value = aws_subnet.ecom-public
}

我试图通过创建一个结合服务名称、priv、公共子网 id、实例计数(2)的本地来实现同样的目的。但问题是我无法做到,因为我无法创建独特的组合键

locals {
 service_subnets = {
    for pair in setproduct(var.service-names, values(var.priv-subnet-ids),values(var.pub-subnet-ids),range(var.instance_count)) :
    "${pair[0]}:${pair[1].availability_zone}-${pair[3]}" => {
      service_name = pair[0]
      priv-subnet       = pair[1]
      pub-subnet = pair[2]
    }
  }
}


 resource "aws_instance" "ecom-instances" {
  for_each = local.service_subnets
  ami           = data.aws_ami.ecom.id
  instance_type = "t3.micro"
  tags = {
    Name = each.value.service_name
    Service = each.value.service_name
  }

  vpc_security_group_ids = [var.instances-sg[each.value.service_name].id]
  subnet_id  = "${split("-", each.value.service_name)[2] == "TEST1" ? each.value.pub-subnet.id  : each.value.priv-subnet.id }"
}

我收到以下错误。

Two different items produced the key "ecom-app-TEST1:ap-south-1c-1" in this 'for' expression. If duplicates are expected, use the ellipsis (...)
│ after the value expression to enable grouping by key.

If i add ... and change it as below then it is converted as tuple and i'm not sure how to get and pass the value from each.value in the aws_instance resource

   locals {
     service_subnets = {
        for pair in setproduct(var.service-names, values(var.priv-subnet-ids),values(var.pub-subnet-ids),range(var.instance_count)) :
        "${pair[0]}:${pair[1].availability_zone}-${pair[3]}" => {
          service_name = pair[0]
          priv-subnet       = pair[1]
          pub-subnet = pair[2]
        }
     ... }
    }

on modules/vm/main.tf line 60, in resource "aws_instance" "ecom-instances":
│   60:   subnet_id  = "${split("-", each.value.service_name)[2] == "TEST1" ? each.value.pub-subnet.id  : each.value.priv-subnet.id }"
│     ├────────────────
│     │ each.value is tuple with 3 elements
│ 
│ This value does not have any attributes.

Please Guide me

标签: terraformterraform-provider-aws

解决方案


You could try adding the index to your for loop and making it part of your name, might help you avoid elipsis/tuple conversion.

locals {
 service_subnets = {
    for index, pair in setproduct(var.service-names, values(var.priv-subnet-ids),values(var.pub-subnet-ids),range(var.instance_count)) :
    "${pair[0]}:${pair[1].availability_zone}-${pair[3]}=${index}" => {
      service_name = pair[0]
      priv-subnet       = pair[1]
      pub-subnet = pair[2]
    }
  }
}

推荐阅读