使用资源的一个好的通用策略for_each
是设计您传递给它的数据结构,以便each.value
在资源块中包含您需要的所有实例数据。
在这种情况下,这意味着for_each
您的资源的表达式aws_instance
将是一个对象映射,其中每个对象都有一个实例配置文件和一个子网 ID。
实现这一目标的一种方法是编写一个for
表达式,将var.profiles
(可能是一个set(string)
值)转换为一个对象映射,以获得您想要的结果。例如:
resource "aws_instance" "k8s" {
for_each = {
# This assigns a subnet to each of the profiles
# by first sorting them by name to produce a list
# and then selecting subnets based on the order
# of the sort result.
for i, profile_name in sort(var.profiles) : profile_name => {
iam_instance_profile = profile_name
subnet_id = element(var.subnets, i)
}
}
ami = data.aws_ami.latest-ubuntu.id
instance_type = "t2.medium"
iam_instance_profile = each.value.iam_instance_profile
subnet_id = each.value.subnet_id
vpc_security_group_ids = [var.security_group]
key_name = var.keyname
}
使用元素依赖count.index
于element
每个项目都有自己的索引,但对于一组字符串来说情况并非如此,所以在上面我曾经转换为一个列表,假设对于这种情况,哪个sort
并不重要只要实例最终大致均匀地分布在子网之间,就会将子网分配给每个实例。
但是,要记住一个很大的含义:如果您var.profiles
稍后添加一个新项目,那么它可能会导致subnet_id
重新分配现有实例,因此需要重新创建这些实例。如果您不希望这是真的,那么您需要以某种方式使每个配置文件的子网选择更加明确,这可以通过制作var.profiles
be alist(string)
而不是 aset(string)
然后记录新的配置文件应该只添加到该列表的末尾,或者您可以将决策上移到模块的调用者中,方法是使var.profiles
自己成为对象映射,然后调用者将为每个配置文件指定一个子网:
variable "profiles" {
type = map(object({
subnet_id = string
}))
}
在这种情况下,您的资源块会变得更简单,因为变量值已经具有合适的形状:
resource "aws_instance" "k8s" {
for_each = var.profiles
ami = data.aws_ami.latest-ubuntu.id
instance_type = "t2.medium"
iam_instance_profile = each.key
subnet_id = each.value.subnet_id
vpc_security_group_ids = [var.security_group]
key_name = var.keyname
}