aws_lb 的动态子网映射

Dynamic subnet mappings for aws_lb

我正在尝试使用 Terraform 创建网络负载平衡器,重要的是它与受保护不被破坏的弹性 IP 相关联。

我有如下代码:

resource "aws_lb" "balancer" {
  name = "${var.name}-nlb"

  internal           = "${var.internal}"
  load_balancer_type = "network"
  subnets            = ["${data.aws_subnet_ids.selected.ids}"]

  subnet_mapping {
    subnet_id     = "someid"
    allocation_id = "someid"
  }

  subnet_mapping {
    subnet_id     = "someid"
    allocation_id = "someid"
  }

  subnet_mapping {
    subnet_id     = "someid"
    allocation_id = "someid"
  }

  tags = "${merge(var.tags,
    map("Terraform", "true"),
    map("Environment", var.environment))}"
}

我要做的是动态地制作 subnet_mapping 块,因为此代码位于模块中,我想根据传入的子网数量创建映射的数量。或者传入预定义的块。

有办法吗?对我来说重要的是相关的弹性 IP 需要保留。

this is now doable in Terraform 0.12 by using the dynamic blocks特征中所述:

文档中显示了比上述链接答案更简单的示例:

resource "aws_security_group" "example" {
  name = "example" # can use expressions here

  dynamic "ingress" {
    for_each = var.service_ports
    content {
      from_port = ingress.value
      to_port   = ingress.value
      protocol  = "tcp"
    }
  }
}

原文:

Terraform 当前不允许您在资源 stanzas/sub 资源上使用 count 元参数。

有一个 issue tracking this on Github 但据我所知目前没有任何工作在做。

在该主题 (apparentlymart) 中回复的 Hashicorp 员工目前正在开发新版本的 HCL,将来可能会支持类似的功能。

一个非常丑陋的解决方案可能是为每个可能的 AZ 数量创建一个资源。前(代码未经测试):

data "aws_availability_zones" "available" {}
resource "aws_lb" "lb_2_azs" {
    count = "${length(data.aws_availability_zones.available.names) == 2 ? 1 : 0 }"
    ... all the rest of the stuff here ...
}
resource "aws_lb" "lb_3_azs" {
    count = "${length(data.aws_availability_zones.available.names) == 3 ? 1 : 0 }"
    ... all the rest of the stuff here ...
}

然后在您的模块中输出类似这样的内容:

output "lb_id" {
    value = "${element(concat(aws_lb.lb_2_azs.*.id, aws_lb.lb_3_azs.*.id, list("")), 0)}"
}

如何处理 LB 可能需要的侦听器和其他资源:

resource "aws_lb_listener" "listener" {
    count = "${length(concat(aws_lb.lb_2_azs.*.id, aws_lb.lb_3_azs.*.id))}"
    load_balancer_arn = "${element(concat(aws_lb.lb_2_azs.*.id, aws_lb.lb_3_azs.*.id, list("")), 0)}"
    ... rest of the resource settings ...
}

我没有测试过以前的代码,但这里有一些我知道有效的代码。我有一个用于 consul 的模块,如果它没有被用于 vault,它会创建一个 NLB:

resource "aws_lb" "consul" {
    name               = "${var.lb_name}"
    count              = "${var.for_vault ? 0 : 1}"
    internal           = true
    subnets            = ["${var.subnet_ids}"]
    load_balancer_type = "network"
    idle_timeout = 60
}

resource "aws_lb_listener" "consul" {
    count             = "${var.for_vault ? 0 : 1}"
    load_balancer_arn = "${aws_lb.consul.arn}"
    port              = 8500
    protocol          = "TCP"

    default_action {
        target_group_arn = "${aws_lb_target_group.consul.arn}"
        type             = "forward"
    }
}

您可以对 aws_lb_target_group 和您需要的任何其他引用 aws_lb 资源的资源使用相同的计数技巧。

为此,您可以使用 Terraform 0.12 中的动态块功能。

resource "aws_lb" "balancer" {
  name               = "${var.name}-nlb"
  load_balancer_type = "network"

  dynamic "subnet_mapping" {
    for_each = aws_subnet.public.*.id
    content {
      subnet_id = subnet_mapping.value
      allocation_id = aws_eip.lb[subnet_mapping.key].id
    }
  }
}