如何在Terraform中同时使用索引与实例值创建OpenStack负载均衡器
在Terraform中遍历OpenStack实例时同时使用实例值与循环索引
问题场景
你已经通过Terraform定义了两个节点输出nodes_1和nodes_2:
output "nodes_1" { value = [ for vm in openstack_compute_instance_v2.type_1_instance[*] : tomap({ name = "${vm.name}", private_ip = "${vm.network[0].fixed_ip_v4}" }) ] } output "nodes_2" { value = [ for vm in openstack_compute_instance_v2.type_2_instance[*] : tomap({ name = "${vm.name}", private_ip = "${vm.network[0].fixed_ip_v4}" }) ] }
并将两者合并为单个列表:
cluster_nodes = concat(module.cluster_compute.nodes_1, module.cluster_compute.nodes_2)
现在需要创建OpenStack负载均衡相关资源,同时要用到实例的name、private_ip以及遍历过程中的循环索引,但当前代码中使用index()函数获取索引的方式存在隐患(比如实例重名时会出错,且索引查找效率低),需要更可靠的实现方式。
解决方案
核心思路是在遍历实例时同时保留索引和实例数据,通过构造包含索引信息的映射来实现,避免依赖index()函数。
1. 构造带索引的实例映射
在locals块中生成一个包含索引和实例详情的映射,用索引-实例名称作为唯一键(避免重名冲突):
locals { cluster_nodes = concat(module.cluster_compute.nodes_1, module.cluster_compute.nodes_2) # 生成包含索引的实例映射,键为"索引-实例名称",值包含索引和实例数据 indexed_nodes = { for idx, node in local.cluster_nodes : "${idx}-${node.name}" => { index = idx data = node } } }
2. 修改负载均衡监听器资源
调整监听器的名称(避免重复命名),并确保count等于实例总数:
resource "openstack_lb_listener_v2" "loadbalancer_listener" { count = length(local.cluster_nodes) name = "lb-listener-${count.index}" loadbalancer_id = openstack_lb_loadbalancer_v2.cluster_loadbalancer.id protocol_port = local.starting_port + count.index }
3. 修改负载均衡池资源
使用带索引的映射遍历,直接通过each.value.index获取索引,关联对应的监听器:
resource "openstack_lb_pool_v2" "load_balancer_pool" { for_each = local.indexed_nodes name = "pool-${each.value.data.name}" listener_id = openstack_lb_listener_v2.loadbalancer_listener[each.value.index].id }
4. 修改负载均衡成员资源
同样使用带索引的映射,直接关联对应的池资源:
resource "openstack_lb_member_v2" "load_balancer_member" { for_each = local.indexed_nodes name = "lb-member-${each.value.data.name}" pool_id = openstack_lb_pool_v2.load_balancer_pool[each.key].id address = each.value.data.private_ip }
关键说明
- 用
${idx}-${node.name}作为for_each的键,既保证了唯一性(即使实例重名也不会冲突),又保留了索引信息。 - 直接通过
each.value.index获取循环索引,比index()函数更可靠高效,避免了列表元素重复导致的索引错误。 - 监听器名称添加
count.index后缀,避免多个监听器重名引发的资源冲突。
内容的提问来源于stack exchange,提问作者sctx
相关产品推荐
相关产品推荐

