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

为何在Ingress规则列表中间新增规则后Terraform计划显示强制替换?

问题

我需要为负载均衡器的Ingress规则添加新IP,因此在variables.tf文件的app_ingress_rules列表变量中间位置新增了一条规则详情块,具体如下:

variables.tf

variable "app_ingress_rules" {
  type = list(object({
    from_port  = number
    to_port    = number
    protocol   = string
    cidr_block = string
  }))
  default = [
     {
         //已存在的ingress_rule1详情
     },
     {
        //已存在的ingress_rule2详情
     },
    
     #此处为列表中间新增的规则详情
     {
          protocol   = "tcp"
          from_port  = 443
          to_port    = 443
          cidr_block = "10.XXX.XX.XXX/32"
     },
     {
         //已存在的ingress_rule3详情
     },
     {
        //已存在的ingress_rule4详情
     }
}

该变量用于在main.tf中创建aws_security_group_rule资源,代码如下:

main.tf

resource "aws_security_group_rule" "ingress_rules" {
  count = length(var.app_ingress_rules)

  type              = "ingress"
  from_port         = var.app_ingress_rules[count.index].from_port
  to_port           = var.app_ingress_rules[count.index].to_port
  protocol          = var.app_ingress_rules[count.index].protocol
  cidr_blocks       = [var.app_ingress_rules[count.index].cidr_block]
  security_group_id = aws_security_group.app_security_group.id
}

原本以为仅新增规则不会影响其他已有规则,但执行terraform plan后结果显示:Plan: 3 to add, 0 to change, 2 to destroy.(示例中原有4条规则,在第3位新增后出现此结果)。为何Terraform会销毁并重建新增位置之后的原有Ingress规则?

原因分析

Terraform 通过count创建资源时,会以列表索引作为资源实例的唯一标识符(例如aws_security_group_rule.ingress_rules[0]对应列表第一个元素)。当你在列表中间插入新元素后:

  • 原索引2的规则(ingress_rule3)现在变成了索引3
  • 原索引3的规则(ingress_rule4)现在变成了索引4

Terraform 会认为原来的ingress_rules[2]和ingress_rules[3]对应的资源已经不存在,需要销毁;同时会创建新的ingress_rules[2](新增的规则)、ingress_rules[3](原ingress_rule3)、ingress_rules[4](原ingress_rule4),这就对应了你看到的3 to add, 2 to destroy的结果。

解决方案

要避免这种销毁重建的问题,推荐使用for_each代替count,基于规则的唯一属性生成稳定的实例键:

修改后的main.tf

resource "aws_security_group_rule" "ingress_rules" {
  for_each = { for rule in var.app_ingress_rules : "${rule.protocol}-${rule.from_port}-${rule.cidr_block}" => rule }

  type              = "ingress"
  from_port         = each.value.from_port
  to_port           = each.value.to_port
  protocol          = each.value.protocol
  cidr_blocks       = [each.value.cidr_block]
  security_group_id = aws_security_group.app_security_group.id
}

这样Terraform会根据规则的协议、端口和CIDR组合生成唯一键,无论列表顺序如何变化,只要规则内容不变,对应的资源实例就不会被销毁重建。如果必须使用count,则只能将新规则追加到列表末尾,不要插入到中间位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 01:15:35