我需要使用 Terraform 在 AWS 中创建多个子网,并希望使该过程尽可能易于重复和标准化。我想创建一个
list
为 maps
的变量,其中包含创建子网所需的信息,如下所示:
my_subnet_map = [
{
name = "subnetA",
cidr_blocks = ["10.0.0.0/24"]
},
{
name = "subnetB",
cidr_blocks = ["10.0.1.0/24", "10.0.2.0/24"]
},
{
name = "subnetC",
cidr_blocks = ["10.0.3.0/24", "10.0.4.0/24"]
},
...
]
我设想能够做这样的事情:
resource "aws_subnet" "private" {
count = ???
vpc_id = var.vpc_id
availability_zone = XXX
cidr_block = var.my_subnet_map[SOME KIND OF LOOKUP]
}
我知道如何使用
count
或 for_each
循环遍历值,但在这种情况下,值具有不同数量的 cidr_blocks
。因此,count
与 list
中的条目数不对应。它对应于 cidr_block
的所有成员中 list
值的总数。
我该如何完成这样的事情?对我来说,它几乎像是某种嵌套的
count
,但我对 Terraform 不够熟悉,不知道如何对其进行建模。想法?
您在此处显示的数据结构是一系列对象,如果声明为输入变量,则可能具有以下类型:
list(object({
name = string
cidr_blocks = set(string)
}))
名称“my_subnet_map”因此有点令人困惑,因为这里没有任何地图。我提到这一点只是因为要完成这项工作,您需要将这个对象列表投影到对象映射中,因为这就是
for_each
所需要的,因此当我们开始从中派生其他集合时,直接使用这些名称将使事情变得不那么混乱。这最初的一个。
这似乎也是一个“子网组”列表——这是您自己发明的概念,我现在将其命名为——其中每个对象代表一组子网。因此,为了清楚起见,我们将其命名为
subnet_groups
,并且我还将添加一些类型显式转换,以便更清楚地了解我们在这里要使用的类型:
locals {
subnet_groups = tolist([
{
name = "subnetA",
cidr_blocks = toset(["10.0.0.0/24"])
},
{
name = "subnetB",
cidr_blocks = toset(["10.0.1.0/24", "10.0.2.0/24"])
},
{
name = "subnetC",
cidr_blocks = toset(["10.0.3.0/24", "10.0.4.0/24"])
},
...
])
}
为了使其达到
aws_subnet
需要的形状,有必要将其展平为每个实际子网(而不是每个子网组)包含一个元素的集合。这是一种方法:
locals {
subnets = toset(flatten([
for group in local.subnet_groups : [
for cidr_block in group.cidr_blocks : {
group_name = group.name
cidr_block = cidr_block
}
]
]))
}
resource "aws_subnet" "private" {
for_each = tomap({
for subnet in local.subnets :
"${subnet.group_name}:${subnet.cidr_block}" => subnet
})
vpc_id = var.vpc_id
cidr_block = each.value.cidr_block
}
分配给
subnets
的表达式旨在构造一组形状如下所示的扁平对象:
toset([
{
group_name = "subnetA"
cidr_block = "10.0.0.0/24"
},
{
group_name = "subnetB"
cidr_block = "10.0.1.0/24"
},
{
group_name = "subnetB"
cidr_block = "10.0.2.0/24"
},
{
group_name = "subnetC"
cidr_block = "10.0.3.0/24"
},
{
group_name = "subnetC"
cidr_block = "10.0.4.0/24"
},
])
for_each
中的
resource
块需要一个具有唯一键的映射来跟踪每个实例,因此在实际的 for_each
表达式中,我再次将其投影到一个映射中,其中一些键包含组名称和CIDR 块以确保它们都是唯一的。使用我们开始的子网组集,这将声明以下资源实例:
aws_subnet.private["subnetA:10.0.0.0/24"]
aws_subnet.private["subnetB:10.0.1.0/24"]
aws_subnet.private["subnetB:10.0.2.0/24"]
aws_subnet.private["subnetC:10.0.3.0/24"]
aws_subnet.private["subnetC:10.0.4.0/24"]
flatten
功能
for_each
资源
for
从其他集合派生集合的表达式