【问题标题】:Terraform Module with Count Can't Have Duplicate Elements带有计数的 Terraform 模块不能有重复的元素
【发布时间】:2018-07-29 17:35:48
【问题描述】:

很难在标题中解释,甚至围绕它形成一个问题,所以我将从一些代码开始(简化为,错误,简单):

resource "digitalocean_domain" "this_domain" {
  name       = "${var.domain}"
  ip_address = "${var.main_ip}"
}

resource "digitalocean_record" "this_a_record" {
  count  = "${length(var.a_records)}"

  domain = "${var.domain}"
  type   = "A"
  name   = "${element(keys(var.a_records), count.index)}"
  value  = "${lookup(var.a_records, element(keys(var.a_records), count.index))}"
}

鉴于上述内容是名为 dns 的模块的一部分,我可以这样称呼它:

module "example_com_dns" {
  source = "./modules/dns"

  domain  = "example.com"
  main_ip = "1.2.3.4"

  a_records = {
    "@"    = "5.6.7.8"
    "self" = "9.10.11.12"
    "www"  = "5.6.7.8"
  }
}

按预期运行。我得到了我期望的A 记录; @、self、www,都指向正确的 IP。

但是,它不能处理重复的名称。例如,放入多个@ 记录会导致只写入其中一个,我猜是因为名称的每次迭代都会覆盖之前的@ 记录。

有没有办法有多个重复的名字?即在上面的例子中,有类似的东西:

    ....
    "@" = "5.6.7.8"
    "@" = "20.21.22.23"
    "@" = "30.31.32.33"
    "self" = "9.10.11.12"
    "www" = 5.6.7.8"
    ...

【问题讨论】:

    标签: digital-ocean terraform


    【解决方案1】:

    在这种情况下,您应该将 A 记录放入 list 中,而不是使用 keys 来获取 ma​​p keys

    a_records = [ 
      ["@" , "5.6.7.8"], 
      ["@" , "7.6.7.8"], 
      ["@" , "9.9.9.9"], 
      ["self", "7.10.11.12"], 
      ["self", "11.11.111.11"], 
      ["self", "12.12.12.12"], 
      ["self", "13.13.13.13"], 
      ["www" , "14.14.14.14"] 
    ] 
    

    并将 namevalue 指定为

    name = "${element(var.a_records[count.index],0)}" 
    value = "${element(var.a_records[count.index],1)}"
    

    你会得到你想要的所有重复的A记录

    以下是一个简单的工作示例,说明如何执行此操作。您可以将代码剪切并粘贴到功能性 terraform 会话中,它将正常运行并创建重复的 A 记录。

    您需要扩展示例以满足您对外部模块等的需求。

    variable "a_records" { default = [
        ["@"   , "5.6.7.8"],
        ["@"   , "7.6.7.8"],
        ["@"   , "9.9.9.9"],
        ["self", "7.10.11.12"],
        ["self", "11.11.111.11"],
        ["self", "12.12.12.12"],
        ["self", "13.13.13.13"],
        ["www" , "14.14.14.14"],
        ["www" , "14.14.14.14"]
      ]
    }
    
    variable domain { default = "example20180731.com" }
    variable main_ip { default = "1.1.1.1" }
    
    resource "digitalocean_domain" "this_domain" {
      name       = "${var.domain}"
      ip_address = "${var.main_ip}"
    }
    
    resource "digitalocean_record" "this_a_record" {
      depends_on = ["digitalocean_domain.this_domain"]
      count  = "${length(var.a_records)}"
    
      domain = "${var.domain}"
      type   = "A"
      name   = "${element(var.a_records[count.index],0)}"
      value  = "${element(var.a_records[count.index],1)}"
    }
    

    这是另一个例子。它展示了如何使用通过模块提供的外部数据来做到这一点。它也是可以复制并粘贴到功能性 terraform 会话中的代码,并且可以按原样工作。

    create-dup-A-records.tf

    module "dns" {
      source = "./modules/dns"
    }
    
    variable domain { default = "example20180731.com" }
    variable main_ip { default = "1.1.1.1" }
    
    resource "digitalocean_domain" "this_domain" {
      name       = "${var.domain}"
      ip_address = "${var.main_ip}"
    }
    
    resource "digitalocean_record" "this_a_record" {
      depends_on = ["digitalocean_domain.this_domain"]
      count  = "${length(module.dns.a_records_in_dns_module)}"
    
      domain = "${var.domain}"
      type   = "A"
      name   = "${element(module.dns.a_records_in_dns_module[count.index],0)}"
      value  = "${element(module.dns.a_records_in_dns_module[count.index],1)}"
    }
    

    ./modules/dns/dns.tf

    variable "a_records" { default = [
        ["@"   , "5.6.7.8"],
        ["@"   , "7.6.7.8"],
        ["@"   , "9.9.9.9"],
        ["self", "7.10.11.12"],
        ["self", "11.11.111.11"],
        ["self", "12.12.12.12"],
        ["self", "13.13.13.13"],
        ["www" , "14.14.14.14"],
        ["www" , "14.14.14.14"]
     ]
    }
    
    output "a_records_in_dns_module" {
        value = "${var.a_records}"
    }
    

    【讨论】:

    • 感谢您抽出宝贵时间回答 :) 暂时搁置 @A 记录是否需要唯一的论点(我不认为他们这样做:tools.ietf.org/html/rfc1035),我'我专门询问如何在 Terraform 中实现这一点。在循环之外做同样的事情效果很好(创建了多个“@”A记录)。
    • 在这种情况下,而不是使用 keys 来获取映射键,您应该将 A 记录放入如下列表中:code a_records = [ ["@" , "5.6 .7.8"], ["@", "7.6.7.8"], ["@", "9.9.9.9"], ["self", "7.10.11.12"], ["self", "11.11.111.11 "], ["self", "12.12.12.12"], ["self", "13.13.13.13"], ["www" , "14.14.14.14"] ] code 并分配“名称”和“值” “ as code name = "${element(var.a_records[count.index],0)}" value = "${element(var.a_records[count.index],1)}" code 而你将获得您想要的所有重复的 A 记录。
    • @Don 您应该相应地更新您的答案,因为这似乎是解决方案。
    • 不幸的是,element() 有这个限制:“这个函数只适用于平面列表”——来自terraform.io/docs/configuration/… 事实上我得到“元素:参数 1 应该是类型列表,得到类型字符串”
    • 在上面的代码中,element() 确实根据需要得到了一个列表,并产生了重复的 A 记录而没有任何错误。您可以发布您正在使用的代码吗?听起来您在设置列表时语法错误。我还将用一个简单的工作示例更新答案,希望您可以扩展以适应您的情况。
    【解决方案2】:

    原来这是 Terraform 的限制:

    https://github.com/hashicorp/terraform/issues/18573#event-1765829698

    @don 大部分都在他的回答中,但你不能使用传入的变量来完成这项工作。您需要使用split hack 将其作为字符串传递,然后将其设为列表,如上述链接问题中所述:

    从 main.tf 调用:

    module "example_com_dns" {
      source = "./modules/dns"
    
      domain  = "example.com"
      main_ip = "${lookup(var.example_com_dns, "at01")}"
    
      a_records = [
        "@ 5.6.7.8",
        "@ 7.6.7.8",
      ]
    }
    

    dns.tf 模块:

    resource "digitalocean_record" "this_a_record" {
      depends_on = ["digitalocean_domain.this_domain"]
      count  = "${length(var.a_records)}"
    
      domain = "${var.domain}"
      type   = "A"
      name   = "${element(split(" ", var.a_records[count.index]),0)}"
      value  = "${element(split(" ", var.a_records[count.index]),1)}"
    }
    

    对于其他试图通过 Google 搜索执行此操作的人;我的建议是不要。 0.12 即将推出,并将修复所有这些疯狂的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-18
      • 2016-08-02
      • 2015-11-09
      • 1970-01-01
      • 2021-07-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多