Terraform同资源count与for_each替代实现及NEG数据访问问题
Terraform跨可用区查询NEG并配置后端服务的实现方案
核心问题根源
Terraform 语法层面严格要求同一资源/数据源块内,count 与 for_each 两个元参数互斥,无法在同一个块中同时实现「遍历所有后端配置」+「遍历所有可用区」两个维度的循环,直接在块内同时写两个元参数会触发语法报错。
正确实现步骤
1. 用本地值构建双维度遍历的唯一映射
首先把「后端配置条目」和「可用区列表」做笛卡尔积组合,生成满足 for_each 要求的、带全局唯一键的扁平映射,作为数据源的遍历输入:
locals { neg_query_target = merge([ # 外层遍历所有后端配置 for backend_key, backend_conf in var.backends : { # 内层遍历所有可用区,生成唯一组合键 for zone in var.all_zone : "${backend_key}-${zone}" => { neg_name = backend_conf.neg_name zone = zone } } ]...) }
按照给出的示例,当var.backends只有default条目、var.all_zone包含3个可用区时,生成的映射会包含3个唯一键值对,键分别为default-asia-southeast1-a、default-asia-southeast1-b、default-asia-southeast1-c,每个键对应的值包含要查询的NEG名称和所在可用区。
2. 改写NEG查询的数据源块
删除原有块里的count元参数,改用第一步生成的映射作为for_each的输入:
data "google_compute_network_endpoint_group" "get_neg" { for_each = local.neg_query_target zone = each.value.zone name = each.value.neg_name }
注意:这种写法下,数据源的返回结构是映射类型,而非count对应的列表类型。映射的键就是第一步生成的组合字符串,值是每个可用区下查询到的NEG资源对象(包含id、name、zone等属性)。
3. 提取所有NEG的ID配置到后端服务
很多人用for_each的时候卡壳,就是因为习惯了count返回的列表结构,直接写splat表达式取不到值。实际上只要先用values()函数把映射的所有值转为列表,后续提取属性的逻辑和之前使用count时完全一致:
resource "google_compute_backend_service" "default" { # ... 原有其他后端服务配置 dynamic "backend" { # 先把映射值转列表,再用splat表达式提取所有NEG的ID for_each = values(data.google_compute_network_endpoint_group.get_neg)[*].id content { group = backend.value } } }
常见注意事项
- 生成的组合键必须保证全局唯一,否则for_each会因键冲突报错,上述
后端key-可用区的组合格式在当前场景下可天然满足唯一性要求 - 如果需要过滤部分不需要查询的NEG,只需在生成
neg_query_target的循环块中增加条件判断,后续的ID提取、动态配置逻辑不需要调整 - 不要尝试在同一资源块内混用count和for_each,该语法限制从Terraform 0.13版本开始持续生效,不存在兼容的写法
内容的提问来源于stack exchange,提问作者Fixlensmith
相关产品推荐
相关产品推荐

