【问题标题】:How to access Cloud Run service IPs from Terraform / Pulumi to dynamically create A records?如何从 Terraform / Pulumi 访问 Cloud Run 服务 IP 以动态创建 A 记录?
【发布时间】:2020-06-14 04:19:18
【问题描述】:

我正在使用带有 Pulumi 的 Google Cloud Run(类似于 Terraform)。我对 Cloud Run 的域映射的设置是:

  new gcp.cloudrun.DomainMapping(
    `${prefix}-domain-mapping`,
    {
      location,
      name: 'xxx',
      metadata: {
        namespace: projectId,
      },
      spec: {
        routeName: appService.name,
      },
    },
    {
      dependsOn: [appService],
    },
  )

其中appService 指向 Cloud Run 服务的一个实例。这会成功创建到 Cloud Run 服务的域映射。

接下来我要设置一个带有记录的 DNS 区域:

  const zone = new gcp.dns.ManagedZone(`${prefix}-zone`, {
    name: `${prefix}-zone`,
    dnsName: 'xxx.',
    visibility: 'public',
  })

  const ips = ['xxx', 'xxx', 'xxx', 'xxx']
  new gcp.dns.RecordSet(
    `${prefix}-a-records`,
    {
      name: 'xxx.',
      managedZone: zone.name,
      type: 'A',
      ttl: 3600,
      rrdatas: ips,
    },
    {
      dependsOn: [zone],
      deleteBeforeReplace: true,
    },
  )

上面的代码有效。我有一个 DNS 区域,其中有四个 A 记录指向 4 个不同的 IP 地址,这些 IP 地址指向 Cloud Run 服务。我的问题是:如何自动化上面硬编码的 IP?我希望为 A 记录动态设置 Cloud Run 的 IP 地址。 ips 变量必须指向 Cloud Run 实例的 IP,但我找不到这样做的方法。

或者也许我做错了,应该有另一种方法吗?我的目标是,如果 Cloud Run 服务更新并接收到新 IP,DNS 记录也应该自动更新。我不想手动更新地址。

由于 Pulumi 或多或少等同于 Terraform,因此非常感谢 Terraform 或 Pulumi 中的答案!

【问题讨论】:

  • 您是在映射 DNS 区域(根域)还是 DNS 区域的子域?对于第一种情况,Cloud Run 为 A 记录提供 IP 地址。对于第二种情况,Cloud Run 为 CNAME 记录提供 DNS 名称。
  • 我正在映射一个根域。我可以从 Cloud Run 域映射表中获取 IP,但我希望它是自动化的。
  • 如果您将DomainMapping 分配给mapping 变量,mapping.resourceRecords 不会包含您需要的内容吗?
  • 它有一个记录列表,其中包含 rrdatas 字段。但是,这些记录在运行 Pulumi 自动化时将不可用。并且 API 不会接受 RecordSet 中 rrdatas 字段的 resourceRecords。
  • 它们将在 Pulumi 运行期间可用 - 在创建 DomainMapping 资源之后但在创建 RecordSet 之前 - 你可以分配它,这就是为什么 rrdatas 有 @987654331 @ 类型,而不仅仅是字符串数组。

标签: google-cloud-platform terraform google-cloud-run pulumi


【解决方案1】:

由于这个问题同时被 Pulumi Terraform 标签标记,这里有一个可能的 Terraform 解决方案:

resource "google_cloud_run_domain_mapping" "example" {
  location = "us-central1"
  name     = "xxx"

  metadata {
    namespace = local.project_name
  }

  spec {
    route_name = google_cloud_run_service.app.name
  }
}

resource "google_dns_managed_zone" "example" {
  name       = "${local.prefix}-zone"
  dns_name   = "xxx."
  visibility = "public"
}

locals {
  dns_records = {
    "A" = [
      for rr in google_cloud_run_domain_mapping.example.resource_records :
      rr.rrdata if rr.type == "A"
    ]
    "AAAA" = [
      for rr in google_cloud_run_domain_mapping.example.resource_records :
      rr.rrdata if rr.type == "AAAA"
    ]
  }
}

resource "google_dns_record_set" "example" {
  for_each = local.dns_records

  managed_zone = google_dns_managed_zone.example.name

  name    = "xxx."
  type    = each.key
  ttl     = 3600
  rrdatas = each.value
}

【讨论】:

  • 我认为你需要迭代的资源是google_cloud_run_domain_mapping.example.status[0].resource_records
【解决方案2】:

我没有尝试过运行它,但至少这段代码可以编译:

const mapping = new gcp.cloudrun.DomainMapping(...);

const records = mapping.status.resourceRecords?.apply(rs => rs ?? []) ?? pulumi.output([]);

new gcp.dns.RecordSet(`${prefix}-a-records`, {
    name: 'xxx.',
    managedZone: zone.name,
    type: 'A',
    ttl: 3600,
    rrdatas: records.apply(rs => rs.map(r => r.rrdata)),
}, {
    dependsOn: [zone, mapping],
    deleteBeforeReplace: true,
});

records 共舞是为了在两个层面上摆脱undefined...不确定是否可以简化。

【讨论】:

  • 这很好用。我不知道apply 功能。它有点让我做一个“内部地图”。我还使用它来对数组进行内部过滤,使其只有 A RecordSet 的 A 记录。谢谢!
  • 任何时候您有关于OutputInput 的问题,apply 通常都是答案。一定要学习pulumi.com/docs/intro/concepts/programming-model/#outputs
猜你喜欢
  • 2021-04-14
  • 2020-07-11
  • 2022-01-16
  • 1970-01-01
  • 2018-08-01
  • 2020-01-26
  • 2021-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多