当我们在 terraform 的源模块中使用数据块时,我们遇到了依赖问题。 例子: 考虑我们有 VPC、子网和 Cloudwatch - 如果我们要进行细微更改 Amazon Cloudwatch 中的(更改retention_days)会导致重新创建VPC 和子网。 在我们的例子中,VPC 取决于 Cloudwatch(因为 VPC(vpc_flow_log) 中的 cloud_watch_log_group 块需要 cloudwatch 名称),而子网取决于 VPC(由于子网中使用的 vpc id)。
因此,每当 Cloudwatch 发生微小变化时,它都会强制替换 vpc-flowlog,因为 vpc 是 重新创建,这使得子网也被重新创建。
特别是当我们使用数据块来处理依赖关系时,无论任何提供者如何,我们都会面临这个问题。
请让我知道有关此问题的更多详细信息。
如果我们删除源模块中的数据块,那么它会产生预期的结果。 我们也尝试升级 terraform 和提供程序版本,但没有解决我们的问题。
主.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/子网/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/子网/data.tf
data "aws_vpc" "vpcid" {
tags = {
Name=var.data_vpc_name
}
}
source_modules/子网/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 Results**
terraform plan
module.cloudwatch["logging_01"].aws_cloudwatch_log_group.test: Refreshing state... [id=testdataissuecwg1211q]
module.vpc["vpc_01"].aws_vpc.main: Refreshing state... [id=vpc-0dba4643e6f19061a]
module.vpc["vpc_01"].aws_iam_role.example: Refreshing state... [id=stackissue1qw]
module.vpc["vpc_01"].aws_iam_role_policy.example: Refreshing state... [id=stackissue1qw:stackissue1qw]
module.vpc["vpc_01"].aws_flow_log.example: Refreshing state... [id=fl-0bf918ffe07281dd4]
module.subnet["subnet_01"].aws_subnet.main: Refreshing state... [id=subnet-0ec569f1c4cb9ef15]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
~ update in-place
-/+ destroy and then create replacement
<= read (data resources)
Terraform will perform the following actions:
# module.cloudwatch["logging_01"].aws_cloudwatch_log_group.test will be updated in-place
~ resource "aws_cloudwatch_log_group" "test" {
id = "testdataissuecwg1211q"
name = "testdataissuecwg1211q"
~ retention_in_days = 30 -> 60
tags = {}
# (4 unchanged attributes hidden)
}
# module.subnet["subnet_01"].data.aws_vpc.vpcid will be read during apply
# (depends on a resource or a module with changes pending)
<= data "aws_vpc" "vpcid" {
+ arn = (known after apply)
+ cidr_block = (known after apply)
+ cidr_block_associations = (known after apply)
+ default = (known after apply)
+ dhcp_options_id = (known after apply)
+ enable_dns_hostnames = (known after apply)
+ enable_dns_support = (known after apply)
+ enable_network_address_usage_metrics = (known after apply)
+ id = (known after apply)
+ instance_tenancy = (known after apply)
+ ipv6_association_id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ main_route_table_id = (known after apply)
+ owner_id = (known after apply)
+ state = (known after apply)
+ tags = {
+ "Name" = "testvpc0111"
}
}
# module.subnet["subnet_01"].aws_subnet.main must be replaced
-/+ resource "aws_subnet" "main" {
~ arn = "arn:aws:ec2:us-east-1:************:subnet/subnet-0ec569f1c4cb9ef15" -> (known after apply)
~ availability_zone = "us-east-1c" -> (known after apply)
~ availability_zone_id = "use1-az4" -> (known after apply)
- enable_lni_at_device_index = 0 -> null
~ id = "subnet-0ec569f1c4cb9ef15" -> (known after apply)
+ ipv6_cidr_block_association_id = (known after apply)
- map_customer_owned_ip_on_launch = false -> null
~ owner_id = "************" -> (known after apply)
~ private_dns_hostname_type_on_launch = "ip-name" -> (known after apply)
tags = {
"Name" = "testdatasnet1"
}
~ vpc_id = "vpc-0dba4643e6f19061a" # forces replacement -> (known after apply) #
forces replacement
# (8 unchanged attributes hidden)
}
# module.vpc["vpc_01"].data.aws_cloudwatch_log_group.test_clg will be read during apply
# (depends on a resource or a module with changes pending)
<= data "aws_cloudwatch_log_group" "test_clg" {
+ arn = (known after apply)
+ creation_time = (known after apply)
+ id = (known after apply)
+ kms_key_id = (known after apply)
+ log_group_class = (known after apply)
+ name = "testdataissuecwg1211q"
+ retention_in_days = (known after apply)
+ tags = (known after apply)
}
# module.vpc["vpc_01"].data.aws_iam_policy_document.assume_role will be read during apply
# (depends on a resource or a module with changes pending)
<= data "aws_iam_policy_document" "assume_role" {
+ id = (known after apply)
+ json = (known after apply)
+ 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 will be read during apply
# (depends on a resource or a module with changes pending)
<= data "aws_iam_policy_document" "example" {
+ id = (known after apply)
+ json = (known after apply)
+ statement {
+ actions = [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:DescribeLogGroups",
+ "logs:DescribeLogStreams",
+ "logs:PutLogEvents",
]
+ effect = "Allow"
+ resources = [
+ "*",
]
}
}
# module.vpc["vpc_01"].aws_flow_log.example must be replaced
-/+ resource "aws_flow_log" "example" {
~ arn = "arn:aws:ec2:us-east-1:************:vpc-flow-log/fl-0bf918ffe07281dd4" -> (known after apply)
~ id = "fl-0bf918ffe07281dd4" -> (known after apply)
~ log_destination = "arn:aws:logs:us-east-1:************:log-group:testdataissuecwg1211q" # forces replacement -> (known after apply) # forces replacement
~ log_format = "${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status}" -> (known after apply)
~ log_group_name = "testdataissuecwg1211q" -> (known after apply)
- tags = {} -> null
~ tags_all = {} -> (known after apply)
# (5 unchanged attributes hidden)
}
# module.vpc["vpc_01"].aws_iam_role.example will be updated in-place
~ 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"
}
) -> (known after apply)
id = "stackissue1qw"
name = "stackissue1qw"
tags = {}
# (8 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# module.vpc["vpc_01"].aws_iam_role_policy.example will be updated in-place
~ 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"
}
) -> (known after apply)
# (1 unchanged attribute hidden)
}
Plan: 2 to add, 3 to change, 2 to destroy.
可能是depends_on的原因,你最好使用表达式引用,只需使用 example 代替数据 data_vpc_name 即可
module.vpc.vpc_name
云手表也一样。
来自 Hashicorp 文档:
您应该使用depends_on作为最后的手段,因为它可能会导致 Terraform 创建更保守的计划来取代更多 资源超出必要。例如,Terraform 可能会处理更多值 为未知“(应用后已知)”,因为不确定发生了什么变化 将发生在上游对象上。当您 对模块使用depends_on。
我们建议使用表达式引用来代替depends_on 尽可能暗示依赖关系。表达式引用让 Terraform 了解参考值源自哪个值并避免计划 如果该特定值没有改变,即使其他部分也没有改变 上游对象已计划更改。
https://developer.hashicorp.com/terraform/language/meta-arguments/depends_on