如何基于terraform中的cidr块提取子网id?

如何基于terraform中的cidr块提取子网id?,terraform,terraform-provider-aws,Terraform,Terraform Provider Aws,我在一个区域中创建了vpc和3个子网。我有3个名为jsc、valid、test的服务,我必须为每个服务创建3个实例,我必须从每个区域cidr块传递子网id variable "region" { type = string default = "ap-south-1" } variable "ecom-cidr" { type = string default = "10.0.0.0/16"

我在一个区域中创建了vpc和3个子网。我有3个名为jsc、valid、test的服务,我必须为每个服务创建3个实例,我必须从每个区域cidr块传递子网id

variable "region" {
  type    = string
  default = "ap-south-1"
}
variable "ecom-cidr" {
  type    = string
  default = "10.0.0.0/16"
}

variable "azs" {
  type    = list(any)
  default = ["ap-south-1a", "ap-south-1b", "ap-south-1c"]
}

variable "private-subnets" {
  type    = list(any)
  default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}

variable "public-subnets" {
  type    = list(any)
  default = ["10.0.4.0/28", "10.0.5.0/28", "10.0.6.0/28"]
}


variable "instance_count" {
  type    = string
  default = 3
}

variable "service-names" {
  type    = list(any)
  default = ["valid", "jsc", "test"]

}
resource "aws_subnet" "ecom-private" {
  count                   = length(var.private-subnets)
  vpc_id                  = aws_vpc.ecom-vpc.id
  cidr_block              = element(var.private-subnets, count.index)
  availability_zone       = element(var.azs, count.index)
  map_public_ip_on_launch = false
  tags = {
    Name = "ecom-INT-${element(split("-", element(var.azs, count.index)), 2)}"
  }
}

data "aws_subnet" "priv-subnet-details" {
  vpc_id = aws_vpc.ecom-vpc.id
  count                   = length(var.private-subnets)
  filter {
    name   = "tag:Name"
    values = ["ecom-INT-${element(split("-", element(var.azs, count.index)), 2)}"] # insert values here
  }
  
}
 resource "aws_instance" "ecom-instances" {
    
      count = 3*var.instance_count
    
      ami           = data.aws_ami.ecom.id
      instance_type = "t3.micro"
      subnet_id = <how to fetch>
      tags = {
        Name = "ecom-${element(var.service-names, count.index)}-service"
        Service = "${element(var.service-names, count.index)}"
      }
vpc_security_group_ids = [aws_security_group.ecom-sg["${element(var.service-names, count.index)}"].id]
现在,我必须通过查找名称标记或cidr块将子网id传递到aws实例资源下面

variable "region" {
  type    = string
  default = "ap-south-1"
}
variable "ecom-cidr" {
  type    = string
  default = "10.0.0.0/16"
}

variable "azs" {
  type    = list(any)
  default = ["ap-south-1a", "ap-south-1b", "ap-south-1c"]
}

variable "private-subnets" {
  type    = list(any)
  default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}

variable "public-subnets" {
  type    = list(any)
  default = ["10.0.4.0/28", "10.0.5.0/28", "10.0.6.0/28"]
}


variable "instance_count" {
  type    = string
  default = 3
}

variable "service-names" {
  type    = list(any)
  default = ["valid", "jsc", "test"]

}
resource "aws_subnet" "ecom-private" {
  count                   = length(var.private-subnets)
  vpc_id                  = aws_vpc.ecom-vpc.id
  cidr_block              = element(var.private-subnets, count.index)
  availability_zone       = element(var.azs, count.index)
  map_public_ip_on_launch = false
  tags = {
    Name = "ecom-INT-${element(split("-", element(var.azs, count.index)), 2)}"
  }
}

data "aws_subnet" "priv-subnet-details" {
  vpc_id = aws_vpc.ecom-vpc.id
  count                   = length(var.private-subnets)
  filter {
    name   = "tag:Name"
    values = ["ecom-INT-${element(split("-", element(var.azs, count.index)), 2)}"] # insert values here
  }
  
}
 resource "aws_instance" "ecom-instances" {
    
      count = 3*var.instance_count
    
      ami           = data.aws_ami.ecom.id
      instance_type = "t3.micro"
      subnet_id = <how to fetch>
      tags = {
        Name = "ecom-${element(var.service-names, count.index)}-service"
        Service = "${element(var.service-names, count.index)}"
      }
vpc_security_group_ids = [aws_security_group.ecom-sg["${element(var.service-names, count.index)}"].id]
你能指引我吗

尝试了以下方法,但由于for_每个都包含在应用后计算的子网id,terraform抛出错误。因此我想直接传递子网id,而不是使用for each

locals {
  instance_configs = tomap({
    for idx,pair in setproduct(var.service-names, data.aws_subnet.priv-subnet-details.*.id) :
    "${pair[0]}-${pair[1]}" => {
      service_name = pair[0]
      subnet = pair[1]
    }
  })
}

resource "aws_instance" "ecom-instances" {
   for_each = local.instance_configs
  ami           = data.aws_ami.ecom.id
  instance_type = "t3.micro"
  tags = {
    Name = "ecom-${each.value.service_name}-service"
    Service = each.value.service_name
  }
vpc_security_group_ids = [aws_security_group.ecom-sg[each.value.service_name].id]
subnet_id              = each.value.subnet
}

根据您的描述,您的问题可以更直接地建模为对象映射,其中每个元素表示特定可用性区域的设置:

variable "availability_zones" {
  type = map(object({
    private_subnet = string
    public_subnet  = string
  }))
}
然后,您可以将其指定为如下值,以便清楚地指示哪些CIDR范围属于哪些可用性区域:

  availability_zones = {
    ap-south-1a = {
      private_subnet = "10.0.1.0/24"
      public_subnet  = "10.0.4.0/28"
    }
    ap-south-1b = {
      private_subnet = "10.0.2.0/24"
      public_subnet  = "10.0.5.0/28"
    }
    ap-south-1c = {
      private_subnet = "10.0.3.0/24"
      public_subnet  = "10.0.6.0/28"
    }
  }
现在,您有了一个数据结构,该结构直接符合每个创建这些子网的期望。例如,对于您的专用子网:

resource "aws_subnet" "ecom_private" {
  for_each = var.availability_zones

  vpc_id                  = aws_vpc.ecom-vpc.id
  cidr_block              = each.value.private_subnet
  availability_zone       = each.key
  map_public_ip_on_launch = false
  tags = {
    Name = "ecom-INT-${split("-", each.key)[2]}"
  }
}
这种方法的一个优点是,
aws\u subnet.ecom\u private
现在是从可用区域到子网对象的映射。正如我在对的回答中所提到的,一个特定的地形配置通常不应该使用
数据块
读取它也使用
资源块
管理的相同对象;相反,我们直接参考
资源
块的结果,以便Terraform可以看到对象是如何连接的,从而产生正确的操作顺序

对于问题的第二部分,听起来像是要为每个服务和子网声明一个
aws\u实例。为了实现这一点,我们需要为每个
派生一个新的数据结构,每个服务和子网组合有一个元素。为了找到我通常使用的两个集合的所有组合,在本例中,我们可能会这样使用:

locals {
  service_subnets = {
    for pair in setproduct(var.service_names, values(aws_subnet.ecom_private)) :
    "${pair[0]}:${pair[1].availability_zone}" => {
      service_name = pair[0]
      subnet       = pair[1]
    }
  }
}
此表达式创建从同时包含服务名称和可用性区域名称的复合键到同时包含服务名称和其中一个子网对象的对象的映射。此数据结构现在具有合适的形状,可以声明此集合的每个元素的
aws\u实例
。请注意,这与您尝试的不同,因为这些键仅从配置中直接定义的数据生成:服务名称和可用性区域名称。您的示例不起作用,因为您尝试使用子网id,EC2在创建子网之后才决定使用该子网id

resource "aws_instance" "ecom" {
  for_each = local.service_subnets

  ami           = data.aws_ami.ecom.id
  instance_type = "t3.micro"
  subnet_id     = each.value.subnet.id

  vpc_security_group_ids = [aws_security_group.ecom_sg[each.value.service_name].id]

  tags = {
    Name    = "ecom-${each.value.service_name}-service"
    Service = each.value.service_name
  }
}
因此,这些实例将具有如下地址,其中键仅包括您在配置中直接定义的数据:

  • aws_实例.ecom[“有效:ap-south-1a”]
  • aws_instance.ecom[“valid:ap-south-1b”]
  • aws_实例.ecom[“有效:ap-south-1c”]
  • aws_instance.ecom[“jsc:ap-south-1a”]
  • aws_instance.ecom[“jsc:ap-south-1b”]
  • aws_instance.ecom[“jsc:ap-south-1c”]
  • aws_instance.ecom[“测试:ap-south-1a”]
  • aws_instance.ecom[“测试:ap-south-1b”]
  • aws_instance.ecom[“测试:ap-south-1c”]

请澄清:您是否在使用
数据“aws\u子网”“私有子网详细信息”{…}
块读取您正在使用
资源“aws\u子网”“ecom private”{…}
块创建的子网的详细信息?第二,你说你想传递“子网ID”-哪个子网ID?您有几个子网。为什么要创建
3*var.instance\u count
实例?哪些子网?您有priv子网详细信息和ecom private吗?有什么区别?@marcin priv subnet details只是ecom的一个数据源-private@user10912187为什么不像通常那样创建3个自动缩放组呢?每个ASG都希望计数为3。谢谢你的指导和对我的良好学习