You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Terraform中合并两个变量并用于for_each循环?

解决Terraform变量合并的问题

错误原因

Terraform变量的default字段仅支持静态值或直接引用其他变量,不允许在变量定义中调用函数(如merge、concat),这是语法层面的硬性限制,所以你之前的写法会触发报错。

正确方案:使用本地值(Locals)合并数据

应该通过locals块来处理变量的合并逻辑,而非定义新变量。同时需要注意:你的apps和acl两个Map的键并不直接对应,需要通过共同标识(比如apps.labels.name和acl.ingress字段)关联两者,确保每个应用匹配到对应的ACL规则。

步骤1:定义本地值合并数据

在配置文件中添加locals块,将apps与对应的acl条目合并:

locals {
  merged_vars = {
    for app_key, app_details in var.apps : app_key => merge(
      app_details,
      # 根据应用的labels.name匹配ACL的ingress字段,找到对应配置
      lookup(
        var.acl,
        [for acl_key, acl_details in var.acl : acl_key if acl_details.ingress == app_details.labels.name][0],
        # 无匹配时返回空对象避免报错,可根据需求调整默认值
        {}
      )
    )
  }
}

步骤2:在资源中使用合并后的数据

修改kubernetes_network_policy资源的for_each,引用本地值:

resource "kubernetes_network_policy" "acl" { 
  for_each = local.merged_vars

  metadata {
    name      = format("%s-acl", each.value.acl_name)
    namespace = each.value.acl_name # 注意:可根据实际需求调整,比如改用应用名称而非ACL名称
  }

  spec {
    policy_types = ["Ingress", "Egress"]
    pod_selector {
      match_labels = {
        tier = each.value.labels.tier
      }
    }
    ingress {
      from {
        namespace_selector {
          match_labels = {
            name = each.value.ingress
          }
        }
      }
      ports {
        port     = each.value.port
        protocol = each.value.protocol
      }
    }
    egress {
      to {
        ip_block {
          cidr = each.value.egress
        }
      }
    }
  }
}

额外修正:修复变量定义中的语法错误

你的apps变量存在多余闭合括号的语法问题,修正后如下:

variable "apps" {
  type = map(object({
    app_name    = string
    labels      = map(string)
    annotations = map(string)
    image       = string
  }))
  default = {
    "app1_name" = {
      app_name = "app1_name"
      labels = {
        "name"  = "stream-frontend"
        "tier"  = "web"
        "owner" = "product"
      }
      annotations = {
        "serviceClass"       = "web-frontend"
        "loadBalancer/class" = "external"
      }
      image = "nginx" # 修正原拼写错误nxinx
    }
    "app2_name" = {
      app_name = "app2_name"
      labels = {
        "name"  = "stream-frontend"
        "tier"  = "web"
        "owner" = "product"
      }
      annotations = {
        "serviceClass"       = "web-frontend"
        "loadBalancer/class" = "external"
      }
      image = "nginx"
    }
    "app3_name" = {
      app_name = "app3_name"
      labels = {
        "name"  = "stream-database"
        "tier"  = "shared"
        "owner" = "product"
      }
      annotations = {
        "serviceClass"       = "disabled"
        "loadBalancer/class" = "disabled"
      }
      image = "Mongo"
    }
  }
}

说明

  • locals是Terraform处理动态计算逻辑的标准位置,支持调用所有Terraform函数。
  • 合并逻辑通过for表达式遍历应用,再通过lookup匹配对应ACL规则,确保每个应用能获取到端口、协议等配置。
  • 若存在应用无匹配ACL规则的情况,lookup的默认空对象可避免报错,你也可以添加校验逻辑(如assert)强制要求匹配。

内容的提问来源于stack exchange,提问作者zolo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 19:10:39