aws_lb 的动态子网映射

Posted

技术标签:

【中文标题】aws_lb 的动态子网映射【英文标题】:Dynamic subnet mappings for aws_lb 【发布时间】:2018-08-23 09:09:59 【问题描述】:

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

【问题讨论】:

您真的有不同数量的子网的案例吗?您是否在具有不同数量可用区的多个区域中运行?如果没有,您可以简化很多事情。 取决于,它是我发布到内部存储库的一个模块,我无法假设其他人如何使用它。 不,我不能做出这样的假设,这不是我要问的。所以真正的问题是,我要问的实际上是可能的,因为如果不是(你不能使用 count)那么你是对的,你可以简化它。 那么答案是否定的。 Terraform 目前不允许您动态设置子资源计数。 @krystanhonour 我使用 random_shuffle 管理动态子网,我使用 lifecyle 忽略与子网相关的更改。同样,这很乏味,因为您需要一次又一次地污染 random_shuffle 模块。这就是我管理分散在多个可用区的基础设施的方式。 【参考方案1】:

您可以使用 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
    
  

【讨论】:

是的,最近这已成为一个非问题,将接受这一点,因为升级到新的闪亮修复了问题及其最干净的解决方案。正如在先前接受的答案中提到的那样【参考方案2】:

正如Hendrik's answer 中所述,现在可以通过使用dynamic blocks 功能在 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 元参数。

有一个issue tracking this on Github,但目前还没有任何工作正在处理它 AFAIK。

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

【讨论】:

谢谢,烦人,但看起来我不是唯一需要这个的人。【参考方案3】:

一个非常丑陋的解决方案可能是为每个可能数量的 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 资源。

【讨论】:

你如何处理监听器规则和目标组?您需要为此参考 aws_lb 资源的 Arn,如果它不存在,因为它不是由 count 为 0 创建的,则 Terraform 将出错。

以上是关于aws_lb 的动态子网映射的主要内容,如果未能解决你的问题,请参考以下文章

在linux中,啥是配置静态和动态的IP地址、子网掩码、默认网关,如何实现

Terraform如何获取aws_lb的IP地址

H3C路由器配置——动态路由RIP协议

ES 12 - 配置使用Elasticsearch的动态映射(dynamic mapping)

静态映射和动态映射

驱动学习之静态映射和动态映射