假设我需要在terraform中配置大量的vpc子网。每个子网都有一个cidr,一个名称和一个可用区。因此,在其他配置管理工具中,我可以执行以下操作:
[
{
"name":"subnet1",
"cidr":"10.0.0.1/24",
"az":"us-west-1a"
},
{
"name":"subnet2",
"cidr":"10.0.0.2/24",
"az":"us-west-1b"
}
]
然后迭代该数组。
就我所见,Terraform没有数组/对象的概念。因此,对于单个属性的数组,我只使用一个列表项:
subnets: ["10.0.0.1/24","10.0.0.2/24"]
但这并不允许我将子网命名或放置在我想要的位置。 我知道我也可以在Terraform中使用多个列表,例如:
subnet_names: ["subnet1", "subnet2"]
subnets: ["10.0.0.1/24","10.0.0.2/24"]
subnet_az: ["us-west-1a", "us-west-1b"]
但这让我感到慌乱和反直觉。我看到的最后一个选项是将所有内容混合成一个丑陋的字符串列表,然后将它们拆分为Terraform:
things: ["subnet1__10.0.0.1/24__us-west-1a","subnet2__10.0.0.2/24__us-west-2a"]
但那只是丑陋。
如何在Terraform中处理数组/对象类型的重复?现在我只是明确定义了所有的东西,导致一个简单的vpc定义为300行: - (
答案 0 :(得分:1)
正如您所见,目前Terraform并不支持您尝试在此处创建的结构化数据列表。
如您在问题中显示的那样,有多个平面字符串列表是这个问题的常见解决方案。它有效,但正如您所看到的那样,跟踪哪些值属于那种方式有点违反直觉。
可能产生更具可读性和可维护性的结果的另一种方法是将aws_subnet
资源分解为一个模块,该模块负责处理所有子网始终相同的元素。然后,您可以为每个子网实例化一次模块,仅提供不同的值:
module "subnet1" {
source = "./subnet"
name = "subnet1"
cidr = "10.0.0.1/24"
az = "us-west-1a"
}
module "subnet2" {
source = "./subnet"
name = "subnet2"
cidr = "10.0.0.2/24"
az = "us-west-1b"
}
在许多情况下,AZ和CIDR块之间存在某种系统关系。如果这对您来说是正确的,那么您也可以使用您的模块对这些编号规则进行编码。例如,在subnet
模块中:
variable "region_network_numbers" {
default = {
"us-west-1" = 0
"us-east-1" = 1
"us-west-2" = 2
}
}
variable "az_network_numbers" {
default = {
a = 1
b = 2
}
}
variable "base_cidr_block" {
default = "10.0.0.0/8"
}
variable "az" {
}
data "aws_availability_zone" "selected" {
name = "${var.az}"
}
resource "aws_subnet" "main" {
cidr_block = "${cidrsubnet(cidrsubnet(var.base_cidr_block, 8, var.region_network_numbers[data.aws_availability_zone.selected.region]), 4, var.az_network_numbers[data.aws_availability_zone.selected.name_suffix])}"
# ...
}
使用此功能,只需向模块提供az
参数,系统地从AZ名称生成cidr
和name
。这与the aws_availability_zone
data source示例中显示的概念相同,Terraform存储库本身也有a more complete, elaborate example of this。