Terraform嵌套循环创建ALB目标组及附件报错的解决方案咨询
解决Terraform「Invalid for_each argument」错误:创建ALB目标组及实例附件
问题原因
你遇到的错误是因为local.c的键依赖于aws_lb_target_group.tg的ARN属性——这个属性只有在资源apply阶段才能生成,而Terraform要求for_each的键集合必须在规划阶段就能完全确定。你的原配置用动态生成的ARN来构建键,导致Terraform无法提前预知所有资源实例的标识。
解决方案
核心思路是:用静态、规划阶段可确定的值(比如EC2实例ID和目标端口的组合)作为for_each的键,仅将动态生成的目标组ARN放在映射的值中。
修改后的完整配置
main.tf
resource "aws_lb_target_group" "tg" { for_each = toset(var.target-port) name = "${var.targetgroup-name}-${each.value}" port = each.value protocol = "HTTP" vpc_id = "vpc-571f3830" } # 直接基于已知变量构建目标组附件的映射,键为静态的"实例ID-端口" locals { target_attachments = { for combo in setproduct(var.target, var.target-port) : "${combo[0]}-${combo[1]}" => { target_id = combo[0] port = combo[1] target_group_arn = aws_lb_target_group.tg[combo[1]].arn } } } resource "aws_lb_target_group_attachment" "tg-attach" { for_each = local.target_attachments target_group_arn = each.value.target_group_arn target_id = each.value.target_id port = each.value.port }
variables.tf(无需修改,若要优化类型可调整)
variable "target-port" { type = set(string) default = [ "81" , "82" , "83" , "84" , "85" ] } variable "listenerport" { type = set(string) default = [ "81" , "82" , "83" , "84" , "85" ] } variable "target" { type = set(string) default = ["i-08990bdd2df0" , "i-0d3b9802d7ac"] } variable "targetgroup-name" { default = "terraform-alb-tg" }
关键改动说明
- 简化映射逻辑:去掉了冗余的
local.a/local.b/local.c,直接用setproduct(var.target, var.target-port)生成所有需要的实例-端口组合,这些值都是变量中定义的静态内容,规划阶段即可确定。 - 静态键设计:用
"${combo[0]}-${combo[1]}"(实例ID+端口)作为每个附件资源的唯一键,确保Terraform在规划时就能知道所有需要创建的资源实例。 - 动态值引用:仅将目标组ARN(动态生成的属性)放在映射的值中,Terraform允许
for_each的值包含未知内容,只要键是确定的。 - 移除冗余依赖:无需手动添加
depends_on,因为aws_lb_target_group.tg[combo[1]].arn已经隐式建立了依赖关系,Terraform会自动处理创建顺序。
可选优化:调整变量类型
如果你的端口都是数字,可以把var.target-port的类型改为set(number),更符合实际类型:
variable "target-port" { type = set(number) default = [81, 82, 83, 84, 85] }
对应的目标组配置中port = each.value依然可以正常工作,因为Terraform会自动转换类型。
内容的提问来源于stack exchange,提问作者Wai_Lynn
相关产品推荐
相关产品推荐

