Terraform使用For Each创建多目标组与监听器时的端口类型错误求助
问题场景
尝试通过Terraform的for_each批量创建应用目标组、ALB监听器及路径转发规则,实现基于HTTP路径的流量路由。但执行时aws_lb_listener资源抛出类型错误:
Error: Incorrect attribute value type
on alb.tf line 38, in resource "aws_lb_listener" "app_listener_forward":
38: port = each.value.listeners
├────────────────
│ each.value.listeners is set of string with 5 elementsInappropriate value for attribute "port": number required.
错误原因
aws_lb_listener的port属性要求单个数字值(每个监听器绑定一个唯一端口),但当前变量中listeners是一个包含多个端口的集合,直接将集合赋值给port会导致类型不匹配。此外,原代码按应用(app_one、app_two)遍历var.listeners,但每个应用对应多个端口,这种结构无法直接生成每个端口对应的独立监听器实例。
修复方案
通过局部值(locals)重构变量结构,生成每个端口+应用的唯一组合,让for_each遍历每个组合以创建独立的监听器及对应规则。
步骤1:定义局部值转换结构
添加局部值,将原变量中的应用-多端口结构拆分为每个端口对应的独立条目:
locals { listener_instances = merge([ for app_name, app_config in var.listeners : { for port in app_config.listeners : "${app_name}-${port}" => { app_name = app_name port = port paths = app_config.paths app_port = app_config.app_port } } ]...) }
该局部值会生成类似{"app_one-80": {...}, "app_one-443": {...}, ...}的结构,每个键对应一个唯一的监听器实例。
步骤2:修改监听器资源
调整aws_lb_listener的for_each指向局部值,port属性取单个端口值:
resource "aws_lb_listener" "app_listener_forward" { for_each = local.listener_instances load_balancer_arn = aws_lb.app_alb.arn port = each.value.port protocol = "HTTPS" ssl_policy = "ELBSecurityPolicy-TLS-1-2-Ext-2018-06" certificate_arn = var.ssl_cert default_action { type = "forward" target_group_arn = aws_lb_target_group.app_tg[each.value.app_name].arn } }
步骤3:调整监听器规则资源
同步修改aws_lb_listener_rule的for_each,关联到对应的监听器和目标组:
resource "aws_lb_listener_rule" "app_https_listener_rule" { for_each = local.listener_instances listener_arn = aws_lb_listener.app_listener_forward[each.key].arn action { type = "forward" target_group_arn = aws_lb_target_group.app_tg[each.value.app_name].arn } condition { path_pattern { values = each.value.paths } } }
步骤4:保留目标组资源
目标组仍按应用维度创建,无需修改:
resource "aws_lb_target_group" "app_tg" { for_each = var.listeners name = each.key port = each.value.app_port protocol = "HTTP" target_type = "ip" vpc_id = aws_vpc.app_vpc.id health_check { interval = 130 timeout = 120 healthy_threshold = 10 unhealthy_threshold = 10 } stickiness { type = "lb_cookie" cookie_duration = 86400 } }
说明
修复后,每个端口都会创建独立的HTTPS监听器,默认转发到对应应用的目标组,同时添加路径规则匹配指定路径并转发到同一目标组。局部值的转换确保了for_each的键唯一,避免Terraform资源实例冲突。
内容的提问来源于stack exchange,提问作者Dave Michaels

