Terraform 1.3.7循环传递模块Provider别名时字符串插值报错
Terraform循环传递Provider报错:
A provider configuration reference must not be given in quotes. 问题场景
在Terraform 1.3.7版本中,通过for_each循环调用子模块并尝试传递动态生成的Provider时,触发报错:
A provider configuration reference must not be given in quotes.
原错误代码示例
动态生成Provider的配置
resource "local_file" "cluster_provider" { filename = "${path.module}/cluster-provider.tf" file_permission = "666" content = <<-EOT %{for index, cluster in local.config.cluster_list} # Init cluster config for helm and kubernetes providers for each cluster data "cloud_container_cluster_config" "cluster_config_c${index + 1}" { cluster_name_id = module.k8s_cluster[cluster_${index + 1}].cluster_id resource_group_id = module.k8s_cluster[cluster_${index + 1}].resource_group_id } # Helm provider provider "helm" { alias = "helm_cluster_${index + 1}" kubernetes { host = data.cloud_container_cluster_config.cluster_config_c${index + 1}.host token = data.cloud_container_cluster_config.cluster_config_c${index + 1}.token } } # Kubernetes provider provider "kubernetes" { alias = "kubernetes_cluster_${index + 1}" host = data.cloud_container_cluster_config.cluster_config_c${index + 1}.host token = data.cloud_container_cluster_config.cluster_config_c${index + 1}.token } %{endfor} EOT }
子模块传递Provider的代码
module "k8s_cluster" { for_each = { for index, cluster in local.config.cluster_list : "cluster_${index + 1}" => cluster } providers = { kubernetes = "kubernetes.kubernetes_cluster_${index + 1}" # 报错行 helm = "helm.helm_cluster_${index + 1}" } source = "./cluster-child-module" cloud_account_key = var.account_key resource_group_id = local.resource_group_id region = var.location cluster_name = var.cluster_name # 其他模块属性... }
报错原因
- Provider引用禁止字符串插值:模块
providers块中,不能用带插值的字符串(如"kubernetes.kubernetes_cluster_${index + 1}")引用Provider,Terraform要求Provider引用必须是直接的标识符,不能是字符串形式的插值结果。 - 动态生成Provider配置无效:通过
local_file动态生成.tf文件的方式不符合Terraform的静态解析逻辑——Terraform会在执行前提前解析所有配置文件,动态生成的文件无法被正确识别,导致Provider配置无法加载。
解决方案
步骤1:删除动态生成Provider的local_file资源
直接移除resource "local_file" "cluster_provider"的全部代码,改用静态的多实例Provider配置。
步骤2:用for_each定义多实例Provider
直接为每个集群创建对应的Provider实例,避免动态生成:
# 为每个集群拉取配置数据 data "cloud_container_cluster_config" "cluster_config" { for_each = { for index, cluster in local.config.cluster_list : "cluster_${index + 1}" => cluster } cluster_name_id = module.k8s_cluster[each.key].cluster_id resource_group_id = module.k8s_cluster[each.key].resource_group_id } # 多实例Kubernetes Provider provider "kubernetes" { for_each = data.cloud_container_cluster_config.cluster_config alias = each.key host = each.value.host token = each.value.token } # 多实例Helm Provider provider "helm" { for_each = data.cloud_container_cluster_config.cluster_config alias = each.key kubernetes { host = each.value.host token = each.value.token } }
步骤3:子模块中正确传递Provider
利用each.key直接引用对应的Provider实例,无需字符串插值:
module "k8s_cluster" { for_each = { for index, cluster in local.config.cluster_list : "cluster_${index + 1}" => cluster } providers = { kubernetes = kubernetes[each.key] helm = helm[each.key] } source = "./cluster-child-module" cloud_account_key = var.account_key resource_group_id = local.resource_group_id region = var.location cluster_name = var.cluster_name # 其他模块属性... }
核心说明
- Terraform的Provider配置是静态解析的,必须在执行前就明确存在,不能通过动态生成文件的方式创建。
- 使用
for_each定义多实例Provider时,alias直接复用each.key,保证每个Provider实例与集群标识一一对应,传递时通过provider[each.key]直接引用,完全规避字符串插值的问题。
内容的提问来源于stack exchange,提问作者Somnath Pathak
相关产品推荐
相关产品推荐

