如何在Terraform中通过计数器批量引用同命名规则的资源?
我的Terraform清单里有大量命名规则统一的虚拟机资源,格式为vcd_vapp_vm.worker_1_k8s、vcd_vapp_vm.worker_2_k8s……vcd_vapp_vm.worker_100_k8s,需要在负载均衡器(LB)配置中引用全部或部分这类资源。
现有实现方式
目前我通过声明本地变量k8s_workers手动收集这些资源,代码如下:
k8s_workers = [ vcd_vapp_vm.worker_1_k8s, vcd_vapp_vm.worker_2_k8s, vcd_vapp_vm.worker_3_k8s, vcd_vapp_vm.worker_4_k8s, # 大量其他worker资源 vcd_vapp_vm.worker_100_k8s, ]
随后在LB配置中用dynamic块引用该变量:
dynamic "member" { for_each = local.k8s_workers content { name = member.value.computer_name ip_address = member.value.network.0.ip # 省略其他参数 } }
需求与尝试
我想避免手动逐个粘贴资源到数组的重复操作,尝试过用formatlist生成字符串:
k8s_workers = formatlist("vcd_vapp_vm.worker_%s_k8s", range(1, 100))
但这样得到的是字符串而非实际资源引用。目前临时方案是生成主机名字符串后用dns_a_record_set解析IP传给LB,但这种方式无法直接从Terraform状态中获取数据,希望找到正确的语法实现需求。
解决方案
方法1:通过资源索引访问批量获取
Terraform支持通过资源类型的索引访问语法resourcetype["resource_name"],直接构造资源名称字符串来获取对应的资源对象,无需手动罗列:
locals { k8s_workers = [ for idx in range(1, 101) : vcd_vapp_vm["worker_${idx}_k8s"] ] }
这段代码会自动生成1到100编号的worker资源引用列表,得到的是实际的资源对象,可直接用于后续LB的dynamic块。
方法2:用正则筛选匹配命名规则的资源
如果需要更灵活的筛选(比如匹配所有符合worker_*_k8s格式的资源,不局限固定编号范围),可以用for表达式结合正则匹配:
locals { k8s_workers = [ for vm in vcd_vapp_vm : vm if regex("^worker_\\d+_k8s$", vm.name) ] }
方法3:提前批量创建worker资源(最优解)
如果这些worker资源本身是通过Terraform创建的,建议一开始就用count或for_each批量定义,后续引用会更简洁:
resource "vcd_vapp_vm" "worker_k8s" { count = 100 name = "worker_${count.index + 1}_k8s" # 其他配置参数,差异部分可通过count.index或lookup函数处理 }
之后直接引用vcd_vapp_vm.worker_k8s即可,它本身就是一个资源列表,无需额外收集:
dynamic "member" { for_each = vcd_vapp_vm.worker_k8s content { name = member.value.computer_name ip_address = member.value.network.0.ip # 省略其他参数 } }
注意事项
- 方法1的索引访问要求对应的资源必须存在,否则Terraform会报错。
- 若worker资源的命名规则变动,需同步调整正则或索引构造逻辑。
内容的提问来源于stack exchange,提问作者Andrew

