对您已经尝试过的方法的最小更改的答案类似于以下内容,但它有一些注意事项,我将在后面描述。
variable "instance_types" {
type = list(string)
}
resource "aws_instance" "example" {
count = length(var.instance_types)
instance_type = var.instance_types[count.index]
# etc...
}
上面使用count.index 将aws_instance.example 的编号实例与var.instance_types 中的元素索引相关联,得到我认为您正在寻找的结果。
此解决方案的一个重要警告是,就 Terraform 而言,它使 var.instance_type 中元素的索引成为您的实例的唯一标识符。如果你用上面的代码运行terraform plan,那么你会看到 Terraform 计划实例的地址如下:
-
aws_instance.example[0] 与 instance_type = "t2.micro"
-
aws_instance.example[1] 和 instance_type = "t2.small"
-
aws_instance.example[2] 与 instance_type = "t2.medium"
在设计 Terraform 模块时,重要的是要考虑它将如何响应未来的变化,因为您使用 Terraform 描述的基础架构通常会“无限期地”保持运行,我们希望避免在任何可能的情况下替换它。
鉴于此,请考虑如果您在实例类型列表的开始处添加一个新元素会发生什么:
instance_types = [
"m3.medium",
"t2.micro",
"t2.small",
"t2.medium",
]
如果您再次运行terraform plan,Terraform 将再次将列表元素索引与资源实例标识符相关联,并将制定如下计划:
-
aws_instance.example[0] 与 ~ instance_type = "t2.micro" -> "m3.medium"
-
aws_instance.example[1] 与 ~ instance_type = "t2.small" -> "t2.micro"
-
aws_instance.example[2] 与 ~ instance_type = "t2.medium" -> "t2.small"
-
aws_instance.example[3] 与 + instance_type = "t2.medium"
在 EC2 实例运行后无法更改其实例类型,因此 AWS 提供商将计划替换三个现有实例以应用此更改。这里的“替换”意味着销毁现有对象并创建一个新对象,因此会丢失这些实例上的任何状态并可能导致停机。
对此问题的一个典型答案是对实例使用有意义的标识符字符串,而不仅仅是列表中的位置。您可以通过将变量更改为映射,其键是有意义的标识符,然后使用 for_each 而不是 count:
variable "instance_types" {
type = map(string)
}
resource "aws_instance" "example" {
for_each = var.instance_types
instance_type = each.value
# etc...
}
在这种情况下,您可以使用映射填充 instance_types 变量,其键是向人类维护人员描述每个实例的用途的名称:
instance_types = {
worker = "t2.micro"
web = "t2.small"
database = "t2.medium"
}
当您使用 for_each 时,Terraform 使用地图中的键作为实例标识符,因此您的计划现在看起来像这样:
-
aws_instance.example["worker"] 与 instance_type = "t2.micro"
-
aws_instance.example["web"] 与 instance_type = "t2.small"
-
aws_instance.example["database"] 与 instance_type = "t2.medium"
现在,如果您想稍后添加一个新实例,您可以使用新的唯一键向地图添加一个新元素,Terraform 会理解您打算添加一个新实例并保持所有其他实例不变。