如何从地形中的所有可用区域中挑选不同的子网



当试图通过terraform在AWS中创建elb(经典负载均衡器(时,我发送了一个从另一个模块创建的公共子网ID列表。在这种情况下,我有4个子网,它们横跨3个az。当我试图运行地形时,我有来自az-1a的2个子网,我收到一个错误,说same az can't be used twice for ELB

resource "aws_elb" "loadbalancer" {
name               = "loadbalancer-terraform"
subnets            =  var.public_subnets

listener {
instance_port     = 80
instance_protocol = "http"
lb_port           = 80
lb_protocol       = "http"
}
depends_on = [aws_autoscaling_group.private_ec2]
}

有没有任何方法可以让我从给定的列表中选择子网,这样我就只能从不同的AZ中获得子网id。

subnetid1 -- az1-a
subnetid2 -- az1-b
subnetid3 -- az1-c
subnetid4 -- az1-a

现在我需要得到一个输出子网-1,2和3或子网-2,3和4。

听起来这个问题分解为两个较小的问题:

  1. 确定每个子网的可用性区域
  2. 对于每个不同的可用性区域,选择属于它的任何一个子网

对于第一步,如果我们还没有由当前配置管理的有问题的子网(这里似乎是这样——您从输入变量接收它们(,那么我们可以使用aws_subnet数据源读取给定ID的子网的信息。因为您在这里有多个子网,所以我们将使用资源for_each查找每个子网。

data "aws_subnet" "public" {
for_each = toset(var.public_subnets)
id = each.key
}

以上内容将使data.aws_subnet.public显示为从子网id到子网对象的映射,并且每个子网对象都具有指定每个子网属于哪个区域的availability_zone属性。对于我们的第二步,更方便的是反转该映射,以便密钥是可用区域,值是子网id:

locals {
availability_zone_subnets = {
for s in data.aws_subnet.public : s.availability_zone => s.id...
}
}

上面是一个for表达式,在这种情况下,它使用...后缀来激活分组模式,因为我们预计每个可用性区域会找到多个子网。因此,local.availability_zone_subnets将是一个从可用性区域名称到一个或多个子网ID列表的映射,如下所示:

{
"az1-a" = ["subnetid1", "subnetid4"]
"az1-b" = ["subnetid2"]
"az1-c" = ["subnetid3"]
}

这为我们提供了实现问题的第二部分所需的信息:从每个列表中选择任何一个元素。";任何一个";是通过使用[0]获取第一个元素来获取第一个。

resource "aws_elb" "loadbalancer" {
depends_on = [aws_autoscaling_group.private_ec2]
name    = "loadbalancer-terraform"
subnets = [for subnet_ids in local.availability_zone_subnets : subnet_ids[0]]

listener {
instance_port     = 80
instance_protocol = "http"
lb_port           = 80
lb_protocol       = "http"
}
}

上述解决方案有一些重要的注意事项需要考虑:

  • 取每个子网ID列表的第一个元素意味着配置可能对var.public_subnets中的元素顺序敏感,但上述特定组合隐含地避免了初始for_each中的toset(var.public_subnets),其丢弃CCD_ 13的原始排序并且使得所有下游表达式按照子网id的词法排序来对结果排序。换言之,这将选择id为"的子网;最低";进行词法排序时。

    我真的不喜欢这种决定是隐含的,因为这可能会让未来的维护人员感到困惑,他们可能会改变设计,并惊讶地看到它现在为每个可用区域选择了不同的子网。我可以看到几种不同的方法来缓解这种情况,如果我正在编写一个长寿命的模块:,我可能会同时做到这两种方法

    • 确保variable "public_subnets"的类型约束为type = set(string),而不是type = list(string),以明确此模块丢弃调用方给定的子网顺序。如果您这样做,您可以将toset(var.public_subnets)更改为仅var.public_subnets,因为它将已经是一个集合。

    • 在为每个可用性区域选择第一个子网的最终for表达式中,包括对sort的显式调用。在我的例子中,这个调用与其余部分的实现方式是多余的,但我认为这对未来的读者来说是一个很好的线索,它正在使用词法排序来决定使用哪个子网:

      subnets = [
      for subnet_ids in local.availability_zone_subnets : sort(subnet_ids)[0]
      ]
      

这两项更改实际上都不会立即影响行为,但像这样的添加对未来的维护人员有帮助,因为他们阅读了以前可能不熟悉的模块,所以他们不需要阅读整个模块来理解其中的一小部分。

相关内容

  • 没有找到相关文章