【问题标题】:Reference count resources within a for_each loopfor_each 循环中的引用计数资源
【发布时间】:2021-04-05 16:38:35
【问题描述】:

我目前正在尝试利用 for_each 函数创建 aws_route 资源,并将这些路由与使用 count 函数构建的许多 aws_route_table 资源相关联。我想知道是否有办法让我仍然使用 aws_route 资源中的 for_each 函数并引用 aws_route_table 资源。

我的最终目标是创建 ~5 条路由并将其应用到 ~7 条路由表。

这是我的参考代码:

resource "aws_route_table" "private" {
  vpc_id = aws_vpc.vpc.id
  count  = length(split(",", var.private_subnets))

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = join(",", aws_nat_gateway.nat.*.id)
  }

  route {
    cidr_block = var.stage_vpc_cidr
    vpc_peering_connection_id = var.stage_peering_connection_id
  }

  route {
    cidr_block = var.production_vpc_cidr
    vpc_peering_connection_id = var.production_peering_connection_id
  }

  tags = {
    Name        = "${var.name}-private.${element(split(",", var.azs), count.index)}"
    Department  = var.tag_department
    Lifecycle   = var.tag_lifecycle
    Account     = var.tag_account
    Application = var.tag_application
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_route" "vpn-route" {
  for_each = toset(var.vpn_subnets)
  route_table_id = element(aws_route_table.private.*.id, count.index)
  gateway_id = var.vpn_gateway_id
  destination_cidr_block = each.value
}

和我的变量

variable "vpn_subnets" {
  type = list
  default = ["192.168.0.0/24","192.168.2.0/24","192.168.4.0/24","192.168.5.0/24","192.168.10.0/24","192.168.253.0/24"]
}

【问题讨论】:

    标签: terraform terraform-provider-aws


    【解决方案1】:

    听起来您的要求是为路由表实例和var.vpn_subnets 元素的每个组合都有一个aws_route 实例。

    查找两个集合的所有元素组合的操作称为笛卡尔积,Terraform 有setproduct function 来计算。

    locals {
      route_table_vpn_subnets = [
        for pair in setproduct(aws_route_table.private, var.vpn_subnets) : {
          route_table_name       = pair[0].tags.Name
          route_table_id         = pair[0].id
          destination_cidr_block = pair[1]
        }
      ]
    }
    

    这是使用setproduct 结合for expression 生成一系列对象,这些对象描述了路由表ID 和目标CIDR 块的所有组合,如下所示:

    [
      {
        route_table_name       = "example-private.0"
        route_table_id         = "rtb-12323453"
        destination_cidr_block = "192.168.0.0/24"
      },
      {
        route_table_name       = "example-private.0"
        route_table_id         = "rtb-12323453"
        destination_cidr_block = "192.168.2.0/24"
      },
      # ...
      {
        route_table_name       = "example-private.1"
        route_table_id         = "rtb-abcd"
        destination_cidr_block = "192.168.0.0/24"
      },
      {
        route_table_name       = "example-private.1"
        route_table_id         = "rtb-abcd"
        destination_cidr_block = "192.168.2.0/24"
      },
      # ...
    ]
    

    此数据结构现在满足for_each 的两个关键要求:

    • 我们要创建的每个实例都有这个集合的一个元素。

    • 每个对象都有一组属性,这些属性可以共同用作由配置中决定的值构建的唯一标识符,而不是由远程系统决定的值。

      在这种情况下,通过同时包含 route_table_nameroute_table_id 来提供服务,因为名称是由您的配置选择的,而 id 是由远程系统选择的,因此 id 不适合用作实例标识符。

    要在for_each 中使用它,我们只需多做一步,将其投影到映射中,将这些唯一的属性值组合成唯一的字符串键:

    resource "aws_route" "vpn" {
      for_each = {
        for obj in local.route_table_vpn_subnets :
        "${obj.route_table_name}:${obj.destination_cidr_block}" => obj
      }
    
      route_table_id         = each.value.route_table_id
      gateway_id             = var.vpn_gateway_id
      destination_cidr_block = each.value.destination_cidr_block
    }
    

    这里for表达式中的关键表达式是告诉Terraform为这些实例分配如下地址,这应该满足所有实例唯一的要求:

    • aws_route.vpn["example-private.0:192.168.0.0/24"]

    • aws_route.vpn["example-private.0:192.168.0.2/24"]

    • ...

    • aws_route.vpn["example-private.1:192.168.0.0/24"]

    • aws_route.vpn["example-private.1:192.168.0.2/24"]

    • ...


    请注意,由于您为路由表使用数字索引,因此如果您更改 var.private_subnets 拆分中的元素数,则可能会导致路由表重新编号。因为数字是名称的一部分,而名称是每个路由实例的唯一键的一部分,这也会导致路由实例被重新编号,我之所以提到这一点只是因为使用for_each 的一个典型原因是避免这种重新编号。

    您可能会遵循不同的设计,您可以使用满足上述for_each 的两个条件的对象集合来描述路由表,这样路由表实例也可以使用for_each 声明有意义的唯一键,但这将是超出您所要求的范围的非常重要的更改,因此我不会在这里详细介绍。

    【讨论】:

    • 哇,谢谢你的回答。您不仅提供了答案,还帮助我理解了它背后的逻辑!顺便说一句,destination_cidr_block 应该设置为等于 each.value.destination_cidr_block 而不是 each.value.route_table_id。再次感谢您!
    猜你喜欢
    • 2021-11-25
    • 2021-10-04
    • 2020-02-12
    • 2021-10-06
    • 2021-01-17
    • 2021-05-20
    • 2020-12-17
    • 2020-09-03
    • 1970-01-01
    相关资源
    最近更新 更多