1

我正在尝试使用 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 需要保留。

4

3 回答 3

7

为此,您可以使用 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
    }
  }
}
于 2019-09-02T17:42:52.143 回答
2

正如Hendrik 的回答中提到的,这现在可以通过使用dynamicblocks功能在 Terraform 0.12 中实现:

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

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 目前不允许您count在资源节/子资源上使用元参数。

在 Github 上跟踪此问题存在一个问题,但目前没有任何工作正在对其进行 AFAIK。

Hashicorp 员工在该线程中做出回应(显然是mart )目前正在开发新版本的 HCL,该版本将来可能会支持类似的东西。

于 2018-03-15T12:09:02.590 回答
0

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

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 模块,如果它不用于保险库,它会创建一个 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 资源。

于 2018-03-15T19:17:47.283 回答