在Terraform中使用for_each引用GCP Pub/Sub Topic资源名称
团队使用Terraform部署GCP资源,已有两个Pub/Sub Topic定义在dead_letter_topics.tf文件中:
# dead_letter_topcs.tf resource "google_pubsub_topic" "primary_dead_letter" { name = "primary-dead-letter" labels = { role = "dead-letter" qname = "primary" } message_retention_duration = "1209600s" } resource "google_pubsub_topic" "secondary_dead_letter" { name = "secondary-dead-letter" labels = { role = "dead-letter" qname = "secondary" } message_retention_duration = "1209600s" }
为避免重复编写订阅资源,尝试在my_deadletter_subscriptions.tf中用for_each批量创建订阅:
# my_deadletter_subscriptions.tf locals { queue_names = toset(["primary", "secondary"]) } resource "google_pubsub_subscription" "deadletter_gcs" { for_each = local.queue_names name = "deadletter-gcs-${each.key}" topic = "google_pubsub_topic.${each.key}_dead_letter.name" enable_message_ordering = false enable_exactly_once_delivery = false cloud_storage_config { ... more ... } }
执行时触发错误:
Error: Error creating Subscription: googleapi: Error 400: Invalid resource name given (name=projects/mygcpproject/topics/google_pubsub_topic.primary_dead_letter.name).
Refer to Pub/Sub资源命名规范了解更多信息。
需要实现:不重复编写订阅资源,通过queue_names变量正确引用已创建的Topic名称。
问题根源
你直接将字符串"google_pubsub_topic.${each.key}_dead_letter.name"赋值给topic参数,Terraform没有将其解析为资源引用,而是直接把这个字符串作为Topic名称传递给GCP,导致GCP识别到无效的资源路径。
正确实现方式
方式1:通过资源映射动态引用(推荐)
建立队列名到Topic资源的映射,直接引用资源的id属性(GCP要求的完整资源路径):
# my_deadletter_subscriptions.tf locals { queue_names = toset(["primary", "secondary"]) # 映射队列名到对应的Topic资源 topic_map = { primary = google_pubsub_topic.primary_dead_letter secondary = google_pubsub_topic.secondary_dead_letter } } resource "google_pubsub_subscription" "deadletter_gcs" { for_each = local.queue_names name = "deadletter-gcs-${each.key}" # 引用对应Topic的完整资源ID topic = local.topic_map[each.key].id enable_message_ordering = false enable_exactly_once_delivery = false cloud_storage_config { ... more ... } }
这种方式直接关联Terraform资源,后续如果Topic的名称或路径变化,订阅代码会自动同步,无需手动修改。
方式2:按命名规则拼接Topic路径(不推荐)
如果Topic的命名规则固定(比如[queue-name]-dead-letter),可以手动拼接完整资源路径,但这种方式硬编码规则,灵活性差:
# 需要提前定义gcp_project_id变量 topic = "projects/${var.gcp_project_id}/topics/${each.key}-dead-letter"
后续扩展优化
如果后续要新增更多Topic,且资源名称始终遵循${queue-name}_dead_letter的格式,可以优化topic_map的生成逻辑,避免手动维护映射关系:
locals { queue_names = toset(["primary", "secondary", "tertiary"]) # 自动生成队列名到Topic资源的映射 topic_map = { for qname in local.queue_names : qname => lookup(google_pubsub_topic, "${qname}_dead_letter") } }
这样只要在queue_names中新增队列名,同时在dead_letter_topics.tf中创建对应的google_pubsub_topic.${qname}_dead_letter资源,订阅就会自动生成。
内容的提问来源于stack exchange,提问作者rlandster

