在 terraform 中循环跨模块

loop across modules in terraform

我需要在 GCP 中构建大约 30 个发布子主题,为发布子主题创建每个模块是一个繁琐的过程,有没有更好的处理方法?

module "a" {
  source       = ""
  project_id   = var.project_id
  topic        = var.a["topic_name"]
  topic_labels = var.a["topic_labels"]
  pull_subscriptions = [
    {
      name                    = var.a["pull_subscription_name"]
      ack_deadline_seconds    = var.a["ack_deadline_seconds"]
      max_delivery_attempts   = var.a["max_delivery_attempts"]
      maximum_backoff         = var.maximum_backoff
      minimum_backoff         = var.minimum_backoff
      expiration_policy       = var.expiration_policy
      enable_message_ordering = true
    }
  ]
}

module "b" {
  source       = ""
  project_id   = var.project_id
  topic        = var.b["topic_name"]
  topic_labels = var.b["topic_labels"]
  pull_subscriptions = [
    {
      name                    = var.b["pull_subscription_name"]
      ack_deadline_seconds    = var.b["ack_deadline_seconds"]
      max_delivery_attempts   = var.b["max_delivery_attempts"]
      maximum_backoff         = var.maximum_backoff
      minimum_backoff         = var.minimum_backoff
      expiration_policy       = var.expiration_policy
      enable_message_ordering = true
    }
  ]
}

在 tfvars 中将值传递给上述模块,如下所示:

a = {
  topic_name             = "abc"
  topic_labels           = { env : "prod", purpose : "a" }
  pull_subscription_name = "abc-sub"
  ack_deadline_seconds   = 600
  max_delivery_attempts  = 3
}

b = {
  topic_name             = "bcd"
  topic_labels           = { env : "prod", purpose : "b" }
  pull_subscription_name = "bcd-sub"
  ack_deadline_seconds   = 600
  max_delivery_attempts  = 3
}

我们能否以某种方式组合 tfvars 中的变量并传入单个模块?

我还想知道维护上述 terraform 脚本以单独保存它们或利用一个模块创建 50 个主题的最佳实践?

谢谢!

您可以为模块使用 for_each 元参数:

https://www.terraform.io/docs/language/meta-arguments/for_each.html

您的变量可以是 for_each 可以通过的一组地图。

话虽这么说,这可能会变得过于复杂,IaC 的一个重要方面是保持简单和明确,因为它在某种程度上是自我记录(这不是省略记录您的工作的正当理由) .

对于两个单独的变量,您的选择有点受限,因为 Terraform 无法将这两个单独的变量视为以系统方式连接。 (每个变量,与 Terraform 中的其他对象一样,完全独立于解决依赖性的观点。)

但是,如果您可以将其重组为地图类型的单个变量,那么您可以使用 resource for_each 系统地为地图的每个元素声明一个实例:

variable "topics" {
  type = map(object({
    labels                 = map(string)
    pull_subscription_name = string
    ack_deadline_seconds   = number
    max_delivery_attempts  = number
  }))
}

module "topic" {
  source   = "..."
  for_each = var.topics

  project_id   = var.project_id
  topic        = each.key
  topic_labels = each.value.labels
  pull_subscriptions = [
    {
      name                    = each.value.pull_scription_name
      ack_deadline_seconds    = each.value.ack_deadline_seconds
      max_delivery_attempts   = each.value.max_delivery_attempts
      maximum_backoff         = var.maximum_backoff
      minimum_backoff         = var.minimum_backoff
      expiration_policy       = var.expiration_policy
      enable_message_ordering = true
    }
  ]
}

对于此示例,我假设您的 topic_name 属性将是实例的合适的唯一键,因此我将其从声明的对象类型中删除,目的是将其放入映射键中。换句话说,此 topics 变量的值应如下所示:

topics = {
  abc = {
    labels                 = { env = "prod", purpose = "a" }
    pull_subscription_name = "abc-sub"
    ack_deadline_seconds   = 600
    max_delivery_attempts  = 3
  }
  bcd = {
    labels                 = { env = "prod", purpose = "b" }
    pull_subscription_name = "bcd-sub"
    ack_deadline_seconds   = 600
    max_delivery_attempts  = 3
  }
}

由此,Terraform 将了解您打算使用以下地址声明模块实例:

  • module.topic["abc"]
  • module.topic["bcd"]

因为主题名称是地址的一部分,Terraform 可以识别编辑现有主题对象(不更改其名称)和地图中的 adding/removing 主题之间的区别,将其转换为相应的计划模块内声明的资源实例。

如果重要的是您能够更改远程系统知道的主题名称而无需 Terraform 了解作为单独的删除和创建操作,您可以恢复name 作为该对象类型的属性,然后改为设置 topic = each.value.name,然后地图键将 用于在 Terraform 中进行跟踪,并且在远程系统中根本不可见.