能否通过传入变量让Terraform动态引用资源或数据源块?
问题描述
我在一个Terraform工作区中有一个Kafka集群,希望通过Terraform创建并管理它,同时在另一个工作区中引用该集群。现咨询是否可实现下述理想配置——通过传入变量让Terraform动态引用资源块或数据源块,从而简化重复配置。
现有配置
main.tf
resource "confluent_environment" "env" { display_name = var.env_name } // cluster type for dev-main and dev-qa => basic // cluster type for prod => standard resource "confluent_kafka_cluster" "cluster" { count = var.env_name != "prod-data" ? 1 : 0 display_name = "${var.env_name}-cluster" availability = "SINGLE_ZONE" cloud = "AWS" region = "us-east-1" dynamic "basic" { for_each = var.env_name != "prod" ? [1] : [] content {} } dynamic "standard" { for_each = var.env_name == "prod" ? [1] : [] content {} } environment { id = confluent_environment.env.id } } // 'app-manager' service account is required in this configuration to create topics and create service accounts resource "confluent_service_account" "app_manager" { count = var.env_name != "prod-data" ? 1 : 0 display_name = "${var.env_name}-app-manager" description = "Service account to manage Kafka cluster" } resource "confluent_role_binding" "app_manager_kafka_cluster_admin" { count = var.env_name != "prod-data" ? 1 : 0 principal = "User:${confluent_service_account.app_manager.id}" role_name = "CloudClusterAdmin" crn_pattern = confluent_kafka_cluster.cluster.rbac_crn }
prod_data_main.tf
data "confluent_kafka_cluster" "cluster" { count = var.env_name == "prod-data" ? 1 : 0 display_name = "prod-cluster" environment { id = confluent_environment.env.id } } // create service accounts resource "confluent_service_account" "app_manager_prod_data" { count = var.env_name == "prod-data" ? 1 : 0 display_name = "${var.env_name}-app-manager" description = "Service account to manage Kafka cluster" } resource "confluent_role_binding" "app_manager_kafka_cluster_admin_prod_data" { count = var.env_name == "prod-data" ? 1 : 0 principal = "User:${confluent_service_account.app_manager_prod_data.id}" role_name = "CloudClusterAdmin" crn_pattern = data.confluent_kafka_cluster.cluster.rbac_crn }
理想配置效果
locals { crn_pattern = var.env_name != "prod-data" ? "confluent_kafka_cluster.cluster.rbac_crn" : "data.confluent_kafka_cluster.cluster.rbac_crn" } resource "confluent_environment" "env" { display_name = var.env_name } // cluster type for dev-main and dev-qa => basic // cluster type for prod => standard resource "confluent_kafka_cluster" "cluster" { count = var.env_name != "prod-data" ? 1 : 0 display_name = "${var.env_name}-cluster" availability = "SINGLE_ZONE" cloud = "AWS" region = "us-east-1" dynamic "basic" { for_each = var.env_name != "prod" ? [1] : [] content {} } dynamic "standard" { for_each = var.env_name == "prod" ? [1] : [] content {} } environment { id = confluent_environment.env.id } } data "confluent_kafka_cluster" "cluster" { count = var.env_name == "prod-data" ? 1 : 0 display_name = "prod-cluster" environment { id = confluent_environment.env.id } } // 'app-manager' service account is required in this configuration to create topics and create service accounts resource "confluent_service_account" "app_manager" { display_name = "${var.env_name}-app-manager" description = "Service account to manage Kafka cluster" } resource "confluent_role_binding" "app_manager_kafka_cluster_admin" { principal = "User:${confluent_service_account.app_manager.id}" role_name = "CloudClusterAdmin" crn_pattern = local.crn_pattern }
实现方案
你的理想配置思路完全可行,但需要调整local.crn_pattern的写法——不能直接用字符串引用资源属性,得通过Terraform的条件表达式直接引用对应资源/数据源的属性值。
修正后的完整配置如下:
locals { # 根据环境变量选择对应集群的CRN cluster_crn = var.env_name != "prod-data" ? confluent_kafka_cluster.cluster[0].rbac_crn : data.confluent_kafka_cluster.cluster[0].rbac_crn } resource "confluent_environment" "env" { display_name = var.env_name } // cluster type for dev-main and dev-qa => basic // cluster type for prod => standard resource "confluent_kafka_cluster" "cluster" { count = var.env_name != "prod-data" ? 1 : 0 display_name = "${var.env_name}-cluster" availability = "SINGLE_ZONE" cloud = "AWS" region = "us-east-1" dynamic "basic" { for_each = var.env_name != "prod" ? [1] : [] content {} } dynamic "standard" { for_each = var.env_name == "prod" ? [1] : [] content {} } environment { id = confluent_environment.env.id } } data "confluent_kafka_cluster" "cluster" { count = var.env_name == "prod-data" ? 1 : 0 display_name = "prod-cluster" environment { id = confluent_environment.env.id } } // 'app-manager' service account is required in this configuration to create topics and create service accounts resource "confluent_service_account" "app_manager" { display_name = "${var.env_name}-app-manager" description = "Service account to manage Kafka cluster" } resource "confluent_role_binding" "app_manager_kafka_cluster_admin" { principal = "User:${confluent_service_account.app_manager.id}" role_name = "CloudClusterAdmin" crn_pattern = local.cluster_crn }
关键调整点:
- 把
local.crn_pattern改为直接引用资源/数据源的属性值,而非字符串。因为Terraform会在执行阶段解析资源属性,字符串无法识别为资源引用。 - 由于资源和数据源都用了
count,需要通过索引[0]来访问唯一实例的属性(因为count只会是0或1)。 - 移除了重复的服务账号和角色绑定资源,通过统一的
confluent_service_account.app_manager和confluent_role_binding.app_manager_kafka_cluster_admin实现多环境适配。
这样配置后,当var.env_name为prod-data时,Terraform会使用数据源引用现有集群;其他环境则创建新集群,同时统一管理服务账号和角色绑定,完全实现你想要的简化效果。
内容的提问来源于stack exchange,提问作者AlexLordThorsen
相关产品推荐
相关产品推荐

