4

如果您使用 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 个实例,并且想遍历子网,将每个实例放在一个中。

请问有什么想法吗?谢谢。

4

3 回答 3

3

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

于 2020-07-12T19:02:42.817 回答
0

使用资源的一个好的通用策略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.indexelement每个项目都有自己的索引,但对于一组字符串来说情况并非如此,所以在上面我曾经转换为一个列表,假设对于这种情况,哪个sort并不重要只要实例最终大致均匀地分布在子网之间,就会将子网分配给每个实例。

但是,要记住一个很大的含义:如果您var.profiles稍后添加一个新项目,那么它可能会导致subnet_id重新分配现有实例,因此需要重新创建这些实例。如果您不希望这是真的,那么您需要以某种方式使每个配置文件的子网选择更加明确,这可以通过制作var.profilesbe 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
}
于 2020-07-13T19:26:26.487 回答
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
  }

}

于 2020-07-13T16:58:04.843 回答