aws_lb_target_group_attachment 期间的无效 for_each 参数

Invalid for_each argument during the aws_lb_target_group_attachment

我有两个 target_groups - 一个用于端口 80,另一个用于 443。还有两个实例作为(该 NLB 的)成员,我需要将两个目标组附加到每个实例。这就是我配置的方式,以附加:

// Creates the target-group
resource "aws_lb_target_group" "nlb_target_groups" {
  for_each = {
    for lx in var.nlb_listeners : "${lx.protocol}:${lx.target_port}" => lx
  }
  name                 = "${var.vpc_names[var.idx]}-tgr-${each.value.target_port}"
  deregistration_delay = var.deregistration_delay
  port                 = each.value.target_port
  protocol             = each.value.protocol
  vpc_id               = var.vpc_ids[var.idx]
  proxy_protocol_v2    = true

  health_check {
    port                = each.value.health_port
    protocol            = each.value.protocol
    interval            = var.health_check_interval
    healthy_threshold   = var.healthy_threshold
    unhealthy_threshold = var.unhealthy_threshold
  }
}

// Attach the target groups to the instance(s)
resource "aws_lb_target_group_attachment" "tgr_attachment" {
  for_each = {
    for pair in setproduct(keys(aws_lb_target_group.nlb_target_groups), var.nlb_members.ids) : "${pair[0]}:${pair[1]}" => {
      target_group = aws_lb_target_group.nlb_target_groups[pair[0]]
      instance_id  = pair[1]
    }
  }
  target_group_arn = each.value.target_group.arn
  target_id        = each.value.instance_id
  port             = each.value.target_group.port
  #target_id       = [for tid in range(var.inst_count) : data.aws_instances.nlb_insts.ids[tid]]
}

其中 var.nlb_listeners 定义如下:

nlb_listeners = [
  {
    protocol    = "TCP"
    target_port = "80"
    health_port = "1936"
  },
  {
    protocol    = "TCP"
    target_port = "443"
    health_port = "1936"
  }
]

var.elb_members.ids是这样的:

"ids" = [
    "i-015604f88xxxxxx42",
    "i-0e4defceexxxxxxe5",
  ]

但我收到无效 for_each 参数错误:

Error: Invalid for_each argument

on ../../modules/elb/balencer.tf line 46, in resource "aws_lb_target_group_attachment" "tgr_attachment": 46: for_each = { 47: for pair in setproduct(keys(aws_lb_target_group.nlb_target_groups), var.elb_members.ids) : "${pair[0]}:${pair[1]}" => { 48:
target_group = aws_lb_target_group.nlb_target_groups[pair[0]] 49:
instance_id = pair[1] 50: } 51: }

The "for_each" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this, use the -target argument to first apply only the resources that the for_each depends on.

我无法弄清楚为什么它无效或这个 for_each 无法确定值。知道我在这里做错了什么吗?严重卡在中间,非常感谢任何帮助让我走向正确的方向。

-S

=== 更新:02/23 ==========

@martin-atkins, 我想我理解你所说的,但即使对于已经存在的实例,它似乎也会给我同样的错误。无论如何,这是我的 aws_instance 资源:

resource "aws_instance" "inst" {
  count         = var.inst_count
  instance_type = var.inst_type
  depends_on    = [aws_subnet.snets]
  ami           = data.aws_ami.ubuntu.id

  # the VPC subnet
  subnet_id              = element(aws_subnet.snets.*.id, count.index)
  vpc_security_group_ids = [var.sg_default[var.idx], aws_security_group.secg.id]

  user_data = <<-EOF
          #!/bin/bash
          hostnamectl set-hostname ${var.vpc_names[var.idx]}${var.inst_role}0${count.index + 1}

          # Disable apt-daily.service & wait until `apt updated` has been killed
          systemctl stop apt-daily.service && systemctl kill --kill-who=all apt-daily.service
          while ! (systemctl list-units --all apt-daily.service | egrep -q '(dead|failed)')
          do sleep 1; done
  EOF

  # the public SSH key
  key_name = var.key_info

  tags = merge(
    var.common_tags,
    { "Name" = "${var.vpc_names[var.idx]}${var.inst_role}0${count.index + 1}" }
  )
}

您认为还有什么可以解决这个问题的吗?

-S

EC2 实例 ID 在创建实例之前不会分配,因此 AWS 提供商无法在计划阶段预先计算它们。因此,它们不适合用作 for_each 映射的键的一部分。

相反,您需要为那些由配置本身决定的实例使用其他标识符,而不是由提供程序在应用期间返回的数据决定的。您没有共享实例本身的配置,所以我无法提出具体建议,但如果它们都是由 countfor_each 创建的同一资源的所有实例,那么一个常见的选择是使用每个实例的索引(对于count)或每个实例的唯一键(对于for_each),以便该映射的元素将被添加和删除以与添加和删除的实例本身相对应已删除。

我终于解决了这个问题。不确定这是否是最好的做法,但现在可以毫无错误地为我工作。基本上,我已经像这样更改了数据查找:

// List of instance attributes by role
data "aws_instance" "by_role" {
  for_each = {
    for ic in range(var.inst_count): "${var.inst_role}0${ic+1}" => ic
  }
  instance_tags  = {
    Name = "${var.vpc_names[var.idx]}${each.key}"
  }
  instance_id    = aws_instance.inst[substr(each.key,4,2)-1].id
}

并像这样在 for_each 中使用它:

for_each = {
    for pair in setproduct(keys(aws_lb_target_group.nlb_target_groups), keys(aws_instance.by_role)):
    "${pair[0]}:${pair[1]}" => {
      target_group = aws_lb_target_group.nlb_target_groups[pair[0]]
      member_name  = aws_instance.by_role[pair[1]]
    }
  }

详细信息here,在 Terraform 社区论坛中回答了我自己的问题,以防其他人遇到与我相同的问题。

-圣