Terraform kubernetes_network_policy动态块null值报错解决方案
问题描述
使用kubernetes_network_policy资源配置10条差异化网络策略:1条仅配置ingress规则、1条仅配置egress规则,其余同时配置两类规则。当前动态块关联变量为null时触发报错,需要实现仅当ingress_number等变量存在有效值时才执行对应动态块。
报错信息如下:
Error: Invalid function argument │ │ on main.tf line 16, in resource "kubernetes_network_policy" "example-policy": │ 16: for_each = range(length(each.value.ingress_number)) │ ├──────────────── │ │ each.value.ingress_number is null │ │ Invalid value for "value" parameter: argument must not be null.
原有配置
资源配置代码
resource "kubernetes_network_policy" "example-policy" { for_each = var.inputs metadata { name = each.value.name namespace = each.value.namespace } spec { pod_selector { match_labels = { app = each.value.selector } } policy_types = each.value.policy dynamic "ingress" { for_each = range(length(each.value.ingress_number)) content { ports { port = each.value.ingress_number[ingress.value] protocol = each.value.ingress_protocol[ingress.value] } to { namespace_selector { match_labels = { app = each.value.ingress_label } } } } } dynamic "egress" { for_each = range(length(each.value.egress_number)) content { ports { port = each.value.egress_number[egress.value] protocol = each.value.egress_protocol[egress.value] } to { namespace_selector { match_labels = { app = each.value.egress_label } } } } } } }
variable.tf配置代码
variable "inputs" { type = map(object({ name = string namespace = string selector = string policy = list(string) ingress_number = optional(list(string)) ingress_protocol = optional(list(string)) ingress_label = optional(string) egress_number = optional(list(string)) egress_protocol = optional(list(string)) egress_label = optional(string) })) default = {} }
tfvars配置代码
inputs = { app1 = { name = "apache" namespace = "default" selector = "apache-app" policy = ["ingrees", "Egress"] egress_label = "example" egress_number = ["443", "8080"] egress_protocol = ["TCP", "TCP"] } app2 = { name = "nignx" namespace = "default" selector = "nignix-app" policy = ["ingrees", "Egress"] ingress_label = "play" ingress_number = ["9080", "9320"] ingress_protocol = ["TCP", "TCP"] egress_label = "example" egress_number = ["443", "8080"] egress_protocol = ["TCP", "TCP"] } }
解决方案
报错根因:optional类型属性未显式赋值时默认值为null,直接传入length()函数会触发参数非空校验失败。Terraform动态块的for_each接收空列表/空集合时会自动跳过块生成,不需要额外做逻辑判断,只需要处理null值兜底即可。
步骤1:为可选属性设置默认值(推荐)
直接在变量定义阶段给所有可选属性设置默认值,后续所有引用位置不需要重复判空,是最规范的写法:列表类型默认空列表[],字符串类型默认空字符串""。
修改后的variable.tf:
variable "inputs" { type = map(object({ name = string namespace = string selector = string policy = list(string) ingress_number = optional(list(string), []) ingress_protocol = optional(list(string), []) ingress_label = optional(string, "") egress_number = optional(list(string), []) egress_protocol = optional(list(string), []) egress_label = optional(string, "") })) default = {} }
步骤2:优化动态块遍历逻辑
原写法用range(length())做索引遍历属于冗余写法,直接遍历规则列表即可,空列表时动态块自动不生成,同时减少索引越界风险。
修改后的资源配置:
resource "kubernetes_network_policy" "example-policy" { for_each = var.inputs metadata { name = each.value.name namespace = each.value.namespace } spec { pod_selector { match_labels = { app = each.value.selector } } policy_types = each.value.policy dynamic "ingress" { for_each = each.value.ingress_number content { ports { port = ingress.value protocol = each.value.ingress_protocol[ingress.key] } to { namespace_selector { match_labels = { app = each.value.ingress_label } } } } } dynamic "egress" { for_each = each.value.egress_number content { ports { port = egress.value protocol = each.value.egress_protocol[egress.key] } to { namespace_selector { match_labels = { app = each.value.egress_label } } } } } } }
补充说明
- 如果不想修改变量默认值,也可以在
for_each参数中用try(each.value.ingress_number, [])做null值兜底,效果一致,但可维护性不如统一设置变量默认值。 - 现有tfvars中
policy字段存在拼写错误:ingrees应修正为Ingress,否则Kubernetes无法正确识别策略类型。 - 当前靠同索引匹配端口和协议的写法存在隐患,如果端口列表和协议列表长度不一致会触发报错,后续可将规则配置调整为对象结构,比如
ingress_rules = list(object({port = string, protocol = string})),遍历时不需要依赖索引匹配,稳定性更高。
内容的提问来源于stack exchange,提问作者Eva
相关产品推荐
相关产品推荐

