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

Terraform源模块用data块致资源意外重建问题求助

Terraform Data块依赖导致的资源连锁重建问题

在Terraform源模块中使用data块处理依赖时遇到异常:以VPC、Subnet和CloudWatch为例,对Amazon CloudWatch进行微小变更(如修改retention_days),会触发VPC和Subnet的重建。

具体场景:VPC依赖CloudWatch(VPC流日志需要CloudWatch日志组名称),Subnet依赖VPC(使用VPC ID)。CloudWatch的微小变更会强制重建VPC流日志,进而引发VPC重建,最终导致Subnet被重建。

该问题仅在使用data块处理依赖时出现,与云提供商无关。移除源模块中的data块可得到预期结果,但升级Terraform及提供商版本无法解决此问题。


相关配置代码

main.tf

module "cloudwatch" {
  for_each = var.Amazon_CloudWatch
  source   = "./source_modules/cloudwatch"

  cloud_watch_group_name = each.value["cloud_watch_group_name"]
  retention_days         = each.value["retention_days"]
}

module "vpc" {
  for_each = var.AWS_VPC_Virtual_Private_Cloud
  source   = "./source_modules/vpc"

  vpc_name              = each.value["vpc_name"]
  data_cloud_watch_name = each.value["data_cloud_watch_name"]
  vpc_cidr              = each.value["vpc_cidr"]

  depends_on = [module.cloudwatch]
}

module "subnet" {
  for_each = var.AWS_Subnet
  source   = "./source_modules/subnet"

  subnet_cidr   = each.value["subnet_cidr"]
  subnet_name   = each.value["subnet_name"]
  data_vpc_name = each.value["data_vpc_name"]

  depends_on=[module.vpc]
}

source_modules/vpc/main.tf

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = var.vpc_name
  }
}

resource "aws_iam_role" "example" {
  name               = "example111"
  assume_role_policy = data.aws_iam_policy_document.assume_role.json
}

resource "aws_iam_role_policy" "example" {
  name   = "example111"
  role   = aws_iam_role.example.id
  policy = data.aws_iam_policy_document.example.json
}

resource "aws_flow_log" "example" {
  iam_role_arn    = aws_iam_role.example.arn
  log_destination = data.aws_cloudwatch_log_group.test_clg.arn
  traffic_type    = "ALL"
  vpc_id          = aws_vpc.main.id
}

source_modules/vpc/variables.tf

variable "data_cloud_watch_name" {
  type = string
}

variable "vpc_name" {
  type = string
}

variable "vpc_cidr" {
  type = string
}

source_modules/vpc/data.tf

data "aws_cloudwatch_log_group" "test_clg" {
  name = var.data_cloud_watch_name
}

data "aws_iam_policy_document" "assume_role" {
  statement {
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["vpc-flow-logs.amazonaws.com"]
    }
    
    actions = ["sts:AssumeRole"]
  }
}

data "aws_iam_policy_document" "example" {
  statement {
    effect = "Allow"
    actions = [
      "logs:CreateLogGroup",
      "logs:CreateLogStream",
      "logs:PutLogEvents",
      "logs:DescribeLogGroups",
      "logs:DescribeLogStreams",
    ]
    resources = ["*"]
  }
}

source_modules/subnet/main.tf

resource "aws_subnet" "main" {
  vpc_id     = data.aws_vpc.vpcid.id
  cidr_block = var.subnet_cidr
    
  tags = {
    Name = var.subnet_name
  }
}

source_modules/subnet/data.tf

data "aws_vpc" "vpcid" {
  tags = {
    Name=var.data_vpc_name
  }
}

source_modules/subnet/variables.tf

variable "subnet_cidr" {
  type = string
}
    
variable "subnet_name" {
  type = string
}

variable "data_vpc_name" {
  type = string
}

source_modules/cloudwatch/main.tf

resource "aws_cloudwatch_log_group" "test" {
  name              = var.cloud_watch_group_name
  retention_in_days = var.retention_days
}

source_modules/cloudwatch/variables.tf

variable "cloud_watch_group_name" {
  type = string
}

variable "retention_days" {
  type = number
}

Terraform Plan执行结果

**Terraform Plan 结果**
terraform plan 
module.cloudwatch["logging_01"].aws_cloudwatch_log_group.test: 刷新状态中... [id=testdataissuecwg1211q]
module.vpc["vpc_01"].aws_vpc.main: 刷新状态中... [id=vpc-0dba4643e6f19061a]
module.vpc["vpc_01"].aws_iam_role.example: 刷新状态中... [id=stackissue1qw]
module.vpc["vpc_01"].aws_iam_role_policy.example: 刷新状态中... [id=stackissue1qw:stackissue1qw]
module.vpc["vpc_01"].aws_flow_log.example: 刷新状态中... [id=fl-0bf918ffe07281dd4]
module.subnet["subnet_01"].aws_subnet.main: 刷新状态中... [id=subnet-0ec569f1c4cb9ef15]

Terraform 使用选定的提供商生成以下执行计划。资源操作使用以下符号表示:
  ~ 原地更新
-/+ 销毁后重新创建
 <= 读取(数据资源)

Terraform 将执行以下操作:

  # module.cloudwatch["logging_01"].aws_cloudwatch_log_group.test 将被原地更新
  ~ resource "aws_cloudwatch_log_group" "test" {
        id                = "testdataissuecwg1211q"
        name              = "testdataissuecwg1211q"
      ~ retention_in_days = 30 -> 60
        tags              = {}
        # (4 个未变更属性被隐藏)
    }

  # module.subnet["subnet_01"].data.aws_vpc.vpcid 将在应用阶段读取
  # (依赖于存在待变更的资源或模块)
 <= data "aws_vpc" "vpcid" {
      + arn                                  = (应用后确定)
      + cidr_block                           = (应用后确定)
      + cidr_block_associations              = (应用后确定)
      + default                              = (应用后确定)
      + dhcp_options_id                      = (应用后确定)
      + enable_dns_hostnames                 = (应用后确定)
      + enable_dns_support                   = (应用后确定)
      + enable_network_address_usage_metrics = (应用后确定)
      + id                                   = (应用后确定)
      + instance_tenancy                     = (应用后确定)
      + ipv6_association_id                  = (应用后确定)
      + ipv6_cidr_block                      = (应用后确定)
      + main_route_table_id                  = (应用后确定)
      + owner_id                             = (应用后确定)
      + state                                = (应用后确定)
      + tags                                 = {
          + "Name" = "testvpc0111"
        }
    }

  # module.subnet["subnet_01"].aws_subnet.main 必须被替换
-/+ resource "aws_subnet" "main" {
      ~ arn                                            = "arn:aws:ec2:us-east-1:************:subnet/subnet-0ec569f1c4cb9ef15" -> (应用后确定)
      ~ availability_zone                              = "us-east-1c" -> (应用后确定)
      ~ availability_zone_id                           = "use1-az4" -> (应用后确定)
      - enable_lni_at_device_index                     = 0 -> null
      ~ id                                             = "subnet-0ec569f1c4cb9ef15" -> (应用后确定)
      + ipv6_cidr_block_association_id                 = (应用后确定)
      - map_customer_owned_ip_on_launch                = false -> null
      ~ owner_id                                       = "************" -> (应用后确定)
      ~ private_dns_hostname_type_on_launch            = "ip-name" -> (应用后确定)
        tags                                           = {
            "Name" = "testdatasnet1"
        }
      ~ vpc_id                                         = "vpc-0dba4643e6f19061a" # 强制替换 -> (应用后确定) # 
强制替换
        # (8 个未变更属性被隐藏)
    }

  # module.vpc["vpc_01"].data.aws_cloudwatch_log_group.test_clg 将在应用阶段读取
  # (依赖于存在待变更的资源或模块)
 <= data "aws_cloudwatch_log_group" "test_clg" {
      + arn               = (应用后确定)
      + creation_time     = (应用后确定)
      + id                = (应用后确定)
      + kms_key_id        = (应用后确定)
      + log_group_class   = (应用后确定)
      + name              = "testdataissuecwg1211q"
      + retention_in_days = (应用后确定)
      + tags              = (应用后确定)
    }

  # module.vpc["vpc_01"].data.aws_iam_policy_document.assume_role 将在应用阶段读取
  # (依赖于存在待变更的资源或模块)
 <= data "aws_iam_policy_document" "assume_role" {
      + id   = (应用后确定)
      + json = (应用后确定)

      + statement {
          + actions = [
              + "sts:AssumeRole",
            ]
          + effect  = "Allow"

          + principals {
              + identifiers = [
                  + "vpc-flow-logs.amazonaws.com",
                ]
              + type        = "Service"
            }
        }
    }

  # module.vpc["vpc_01"].data.aws_iam_policy_document.example 将在应用阶段读取
  # (依赖于存在待变更的资源或模块)
 <= data "aws_iam_policy_document" "example" {
      + id   = (应用后确定)
      + json = (应用后确定)

      + statement {
          + actions   = [
              + "logs:CreateLogGroup",
              + "logs:CreateLogStream",
              + "logs:DescribeLogGroups",
              + "logs:DescribeLogStreams",
              + "logs:PutLogEvents",
            ]
          + effect    = "Allow"
          + resources = [
              + "*",
            ]
        }
    }

  # module.vpc["vpc_01"].aws_flow_log.example 必须被替换
-/+ resource "aws_flow_log" "example" {
      ~ arn                      = "arn:aws:ec2:us-east-1:************:vpc-flow-log/fl-0bf918ffe07281dd4" -> (应用后确定)
      ~ id                       = "fl-0bf918ffe07281dd4" -> (应用后确定)
      ~ log_destination          = "arn:aws:logs:us-east-1:************:log-group:testdataissuecwg1211q" # 强制替换 -> (应用后确定) # 强制替换
      ~ log_format               = "${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status}" -> (应用后确定)
      ~ log_group_name           = "testdataissuecwg1211q" -> (应用后确定)
      - tags                     = {} -> null
      ~ tags_all                 = {} -> (应用后确定)
        # (5 个未变更属性被隐藏)
    }

  # module.vpc["vpc_01"].aws_iam_role.example 将被原地更新
  ~ resource "aws_iam_role" "example" {
      ~ assume_role_policy    = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = "sts:AssumeRole"
                      - Effect    = "Allow"
                      - Principal = {
                          - Service = "vpc-flow-logs.amazonaws.com"
                        }
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (应用后确定)
        id                    = "stackissue1qw"
        name                  = "stackissue1qw"
        tags                  = {}
        # (8 个未变更属性被隐藏)

        # (1 个未变更块被隐藏)
    }

  # module.vpc["vpc_01"].aws_iam_role_policy.example 将被原地更新
  ~ resource "aws_iam_role_policy" "example" {
        id     = "stackissue1qw:stackissue1qw"
        name   = "stackissue1qw"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action   = [
                          - "logs:PutLogEvents",
                          - "logs:DescribeLogStreams",
                          - "logs:DescribeLogGroups",
                          - "logs:CreateLogStream",
                          - "logs:CreateLogGroup",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (应用后确定)
        # (1 个未变更属性被隐藏)
    }

计划:添加 2 个资源,变更 3 个资源,销毁 2 个资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 04:05:54