如何让Terraform解析JSON中的变量引用而非当作字符串?
我有一个包含云项目列表的JSON文件(projects.json),项目分布在不同文件夹中,文件内容如下:
{ "project-1": { "project_id": "project-1", "folder_id": "${var.folders.dev.id}" }, "project-2-prd": { "project_id": "project-2-prd", "folder_id": "${var.folders.prd.id}" } }
(注:原JSON中的单引号不符合JSON规范,已修正为双引号以保证合法性)
此前我使用Terraform对象处理这类配置,现在需切换为JSON以动态替换项目列表,但当前的Terraform声明无法正常工作:
locals { projects_config = try( jsondecode(file("${path.module}/projects.json")), {} ) # 其他变量 } module "projects" { for_each = local.projects_config source = "../templates/project_creator" }
问题在于folder_id中的动态变量被当作普通字符串处理,执行Terraform时会出现类似如下的变更:
~ folder_id = "123456789" -> "${var.folders.dev.id}"
我尝试结合jsondecode()和file()函数读取JSON文件,但变量未被识别。请问是否有办法让Terraform像解析.tf.json文件一样处理该JSON,将folder_id视为变量而非字符串?我不想通过文件夹名称与ID映射的方式实现。
Terraform的jsondecode函数仅负责解析JSON结构,不会处理其中的${...}插值语法——这是Terraform配置语言的专属特性,普通JSON文件只会被当作纯数据文件读取,不会触发配置解析逻辑。以下是两种可行的解决方法:
方法1:用templatefile先渲染变量再解析JSON(推荐)
将projects.json当作模板文件使用,通过templatefile函数先完成变量替换,再用jsondecode解析结果:
locals { projects_config = try( jsondecode(templatefile("${path.module}/projects.json", { folders = var.folders })), {} ) }
同时需要修改projects.json里的变量引用格式,去掉var.前缀(因为我们已将var.folders作为参数传入模板):
{ "project-1": { "project_id": "project-1", "folder_id": "${folders.dev.id}" }, "project-2-prd": { "project_id": "project-2-prd", "folder_id": "${folders.prd.id}" } }
这样templatefile会先把变量替换为实际的文件夹ID,再交给jsondecode解析,最终得到的projects_config里的folder_id就是正确的变量值。
方法2:手动用replace替换变量引用(不推荐)
如果不想修改JSON文件内容,可以用replace函数逐个替换字符串中的变量标记:
locals { projects_raw = try(file("${path.module}/projects.json"), "{}") # 逐个替换所有需要解析的变量引用 projects_rendered = replace(projects_raw, "${var.folders.dev.id}", var.folders.dev.id) projects_rendered = replace(projects_rendered, "${var.folders.prd.id}", var.folders.prd.id) projects_config = jsondecode(projects_rendered) }
这种方式需要手动维护所有变量的替换规则,变量数量多的时候会非常繁琐,扩展性差,仅适合临时小场景。
注意:不要尝试让Terraform将普通JSON当作.tf.json处理,两者的定位完全不同——.tf.json是Terraform的配置文件,会被配置解析器完整处理;而普通JSON只是数据文件,仅做结构解析,不会执行配置逻辑。
内容的提问来源于stack exchange,提问作者mr.TKO

