如何基于YAML构建自定义本地变量适配Terraform for_each循环?
问题描述
我们的环境里有个/apps目录,里面放了多个YAML文件,每个文件定义了应用名称和对应的主机名列表。已经用下面的代码把这些文件加载成了本地变量:
applications = [for filename in fileset(path.module, "apps/*.yml") : yamldecode(file(filename))]
local.applications里存着应用和主机名的结构化数据。现在需要生成一个映射列表,每个映射以主机名(hostname.name)为键、应用名称(name)为值,格式如下:
[ {testing-a: testing one}, {testing-b: testing one}, {testing-x: testing-two} ]
这个列表要用来给Terraform资源的for_each循环用,实现批量创建资源,该怎么实现?
解决方案
生成目标映射列表
假设你的YAML文件结构类似这样(比如testing-one.yml):
name: "testing one" hostnames: - name: "testing-a" - name: "testing-b"
另一个testing-two.yml:
name: "testing-two" hostnames: - name: "testing-x"
可以用Terraform的嵌套for表达式结合flatten()函数来生成你要的列表:
locals { applications = [for filename in fileset(path.module, "apps/*.yml") : yamldecode(file(filename))] # 生成目标映射列表 hostname_to_app = flatten([ for app in local.applications : [ for hostname in app.hostnames : { "${hostname.name}" = app.name } ] ]) }
- 内层循环会为每个应用下的主机名生成单独的键值映射,比如
{testing-a: "testing one"} - 外层循环遍历所有加载的应用,收集每个应用对应的主机名映射列表
flatten()函数会把嵌套的列表(比如[[{...}, {...}], [{...}]])转成一维列表,也就是你需要的格式
更适合for_each的优化方案
其实如果是给for_each用,更推荐把它转换成单一的映射(而非列表),因为for_each对映射的支持更友好——每个元素有唯一键,Terraform能更清晰地跟踪资源实例:
locals { applications = [for filename in fileset(path.module, "apps/*.yml") : yamldecode(file(filename))] # 生成单一映射,key为主机名,value为应用名称 hostname_app_map = merge([ for app in local.applications : { for hostname in app.hostnames : hostname.name => app.name } ]...) }
生成的local.hostname_app_map结构是:
{ "testing-a" = "testing one" "testing-b" = "testing one" "testing-x" = "testing-two" }
在资源中使用时:
resource "example_resource" "test" { for_each = local.hostname_app_map name = each.key # 主机名 app_name = each.value # 应用名称 }
内容的提问来源于stack exchange,提问作者leonms.dev
相关产品推荐
相关产品推荐

