使用 for_each 循环

问题描述 投票:0回答:3

如果您使用 for_each 而不是 count,如何获取子网 id? 就我而言,我正在做这样的事情

resource "aws_instance" "k8s" {
    for_each = var.profiles

    ami = data.aws_ami.latest-ubuntu.id
    instance_type = "t2.medium"
    iam_instance_profile = "${each.value}"
    subnet_id = ??????????????
    vpc_security_group_ids = [var.security_group]
    key_name = var.keyname
    
    connection {
    type        = "ssh"
    host        = self.public_ip
    user        = "ubuntu"
    private_key = file(var.private_key_path)

  }
    tags = {
     Name = "${each.key}"
  }
}

这是因为我正在创建类似的实例,但需要为它们分配不同的实例配置文件。

理想情况下,我会做类似的事情

subnet_id = element(var.subnets, count.index )

将实例放置在不同的子网中,但我不认为 countfor_each 可以在同一个块定义中使用。

我必须划分子网和 4 个实例,并且希望循环遍历子网,将每个实例放在一个子网中。

有什么想法吗?

amazon-web-services terraform terraform-provider-aws terraform0.12+
3个回答
4
投票

如果

var.profiles
是一个列表,你可以使用
each.key
来获取每个元素的索引。


1
投票

资源

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
成为
list(string)
而不是
set(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
}

0
投票

您可以将个人资料作为对象列表提供:

例如:

 variable "profiles" {
  type = list(object({
    name = string
    key =  string
  }))
  default = 
    [
      {name = "exemple" , key = "exemplekey" },
      {name = "exemple2" , key = "exemplekey2" }
    ]
}

像这样,

each.key
将包含列表中元素的索引,
each.value
将包含对象{name,key}

所以你的代码会是这样的

resource "aws_instance" "k8s" {
    for_each = var.profiles
    ami = data.aws_ami.latest-ubuntu.id
    instance_type = "t2.medium"
    iam_instance_profile = each.value
    subnet_id = element(var.subnets , each.key)
    vpc_security_group_ids = [var.security_group]
    key_name = var.keyname
    connection {
    type        = "ssh"
    host        = self.public_ip
    user        = "ubuntu"
    private_key = file(var.private_key_path)

  }
    tags = {
     Name = each.value.key
  }

}

© www.soinside.com 2019 - 2024. All rights reserved.