循环遍历列表映射以在一个资源块中为多个域创建 DNS 记录

Loop through map of lists to create DNS records for multiple domains in one resource block

我有几个域,我想创建尽可能多的 DRY 子域。这是原始结构:

variable "domain1" {
  type = list(string)
  default = ["www", "www2"]
}

variable "domain2" {
  type = list(string)
  default = ["www3", "www1"]
}

resource "aws_route53_record" "domain1" {
  for_each = toset(var.domain1)
  
  type = "A"
  name = "${each.key}.domain1.com"
  zone_id = ""
}

resource "aws_route53_record" "domain2" {
  for_each = toset(var.domain2)
  
  type = "A"
  name = "${each.key}.domain2.com"
  zone_id = ""
}

我想合并为一个变量和一个资源块:

variable "subdomains" {
  type = map(list(string))
  default = {
    "domain1.com" = ["www", "www2"]
    "domain2.com" = ["www3", "www1"]
  }
}

resource "aws_route53_record" "domain1" {
  for_each = var.subdomains // make magic happen here...
  
  type = "A"
  name = "${each.subdomain_part}.${each.domain_part}" // ...and here
  zone_id = ""
}

有办法实现吗?

您可以按如下方式展平您的 var.subdomains

locals {
    subdomains_flat = flatten([for domain, subdomains in var.subdomains:
                        [ for subdomain in subdomains:
                            {
                                domain_part = domain
                                subdomain_part = subdomain
                            }
                        ]
                      ])
}

然后:

resource "aws_route53_record" "domain1" {
  for_each = {for idx, val in local.subdomains_flat: idx => val }
  
  type = "A"
  name = "${each.value.subdomain_part}.${each.value.domain_part}" 
  zone_id = ""
}

跟进 关于混乱状态,我不会说混乱......但肯定有一些缺点,该答案中的索引是数字,计划显示资源最终:

  # aws_route53_record.domain1["0"] will be created
  + resource "aws_route53_record" "domain1" {

  # aws_route53_record.domain1["1"] will be created
  + resource "aws_route53_record" "domain1" {

当我们在列表中添加或删除子域时,这可能会产生问题,顺序可能会改变,这将导致资源被销毁并重新创建,这在 route53 记录上并不理想...


这是另一种在资源名称中创建不同索引的方法。
我们仍然使用 flatten 来提取子域,但在这种情况下,我会立即连接,该局部变量已准备好供 aws_route53_record 资源使用。

provider "aws" {
  region = "us-east-2"
}

variable "subdomains" {
  type = map(list(string))
  default = {
    "domain1.com" = ["www", "www2"]
    "domain2.com" = ["www3", "www1"]
  }
}

locals {
  records = flatten([for d, subs in var.subdomains: [for s in subs: "${s}.${d}"]])
}

resource "aws_route53_record" "domain1" {
  for_each = toset(local.records)

  type    = "A"
  name    = each.value
  zone_id = "us-east-1"
}

地形规划如下:

Terraform will perform the following actions:

  # aws_route53_record.domain1["www.domain1.com"] will be created
  + resource "aws_route53_record" "domain1" {
      + allow_overwrite = (known after apply)
      + fqdn            = (known after apply)
      + id              = (known after apply)
      + name            = "www.domain1.com"
      + type            = "A"
      + zone_id         = "us-east-1"
    }

  # aws_route53_record.domain1["www1.domain2.com"] will be created
  + resource "aws_route53_record" "domain1" {
      + allow_overwrite = (known after apply)
      + fqdn            = (known after apply)
      + id              = (known after apply)
      + name            = "www1.domain2.com"
      + type            = "A"
      + zone_id         = "us-east-1"
    }
    ...