Terraform添加资源时aws_rds_cluster_instance被销毁重建问题排查
问题:Terraform管理Aurora集群时异常触发销毁重建
版本信息
- Terraform版本:1.4.6
- AWS Provider版本:4.67.0
背景
使用Terraform管理AWS Aurora MySQL RDS集群,配置中apply_immediately设为false,预期版本升级时集群和实例仅在维护窗口执行原地更新。但添加新资源后执行terraform plan,结果显示aws_rds_cluster及两个aws_rds_cluster_instance需销毁重建,同时将创建aws_secretsmanager_secret、修改aws_route_table。
Terraform配置
基础配置
terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 4.67.0" } } required_version = ">=1.4.6" }
RDS集群及实例配置
resource "aws_rds_cluster" "cluster" { cluster_identifier = "aurora-cluster-demo" engine = "aurora-mysql" db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.default.id db_subnet_group_name = aws_db_subnet_group.database.name engine_version = "8.0.mysql_aurora.3.02.2" availability_zones = [data.aws_availability_zones.available.names[0], data.aws_availability_zones.available.names[1]] database_name = "mydb" master_username = "foo" master_password = "A12dadf125" skip_final_snapshot = true apply_immediately = false enabled_cloudwatch_logs_exports = [ "audit", "error", "general", "slowquery" ] serverlessv2_scaling_configuration { max_capacity = 1.0 min_capacity = 0.5 } lifecycle { ignore_changes = [engine_version] } } resource "aws_rds_cluster_instance" "cluster_instances_reader" { apply_immediately = false auto_minor_version_upgrade = true availability_zone = data.aws_availability_zones.available.names[1] ca_cert_identifier = "rds-ca-2019" cluster_identifier = aws_rds_cluster.cluster.id copy_tags_to_snapshot = false db_parameter_group_name = aws_db_parameter_group.default.id db_subnet_group_name = aws_db_subnet_group.database.name engine = "aurora-mysql" engine_version = "8.0.mysql_aurora.3.02.2" identifier = "database-1-aurora-reader" identifier_prefix = null instance_class = "db.serverless" performance_insights_enabled = true performance_insights_retention_period = 7 promotion_tier = 1 publicly_accessible = false tags = {} tags_all = {} lifecycle { ignore_changes = [engine_version] } } resource "aws_rds_cluster_instance" "cluster_instances_writer" { apply_immediately = false auto_minor_version_upgrade = true availability_zone = data.aws_availability_zones.available.names[0] ca_cert_identifier = "rds-ca-2019" cluster_identifier = aws_rds_cluster.cluster.id copy_tags_to_snapshot = false db_parameter_group_name = aws_db_parameter_group.default.id db_subnet_group_name = aws_db_subnet_group.database.name engine = "aurora-mysql" engine_version = "8.0.mysql_aurora.3.02.2" identifier = "database-1-aurora-writer" identifier_prefix = null instance_class = "db.serverless" performance_insights_enabled = true performance_insights_retention_period = 7 promotion_tier = 1 publicly_accessible = false tags = {} tags_all = {} lifecycle { ignore_changes = [engine_version] } }
Terraform执行计划输出
# aws_rds_cluster.cluster must be replaced -/+ resource "aws_rds_cluster" "cluster" { ~ allocated_storage = 1 -> (known after apply) ~ arn = -> (known after apply) ~ availability_zones = [ # forces replacement - "eu-west-1c", # (2 unchanged elements hidden) ] - backtrack_window = 0 -> null + cluster_identifier_prefix = (known after apply) ~ cluster_members = [ - "database-1-aurora-reader", - "database-1-aurora-writer", ] -> (known after apply) ~ cluster_resource_id = -> (known after apply) - deletion_protection = false -> null ~ endpoint = -> (known after apply) ~ engine_version_actual =-> (known after apply) ~ hosted_zone_id = - -> (known after apply) - iam_database_authentication_enabled = false -> null ~ iam_roles = [] -> (known after apply) ~ id = "aurora-cluster-demo" -> (known after apply) - iops = 0 -> null + kms_key_id = (known after apply) ~ master_user_secret = [] -> (known after apply) + master_user_secret_kms_key_id = (known after apply) ~ network_type = "IPV4" -> (known after apply) ~ port = 3306 -> (known after apply) ~ preferred_backup_window = "22:04-22:34" -> (known after apply) ~ preferred_maintenance_window = "fri:03:03-fri:03:33" -> (known after apply) ~ reader_endpoint = -> (known after apply) ~ storage_encrypted = false -> (known after apply) + storage_type = (known after apply) - tags = {} -> null ~ tags_all = {} -> (known after apply) ~ vpc_security_group_ids = [ - "sg-0ceeef054862e22e7", ] -> (known after apply) # (16 unchanged attributes hidden) # (1 unchanged block hidden) } # aws_rds_cluster_instance.cluster_instances_reader must be replaced -/+ resource "aws_rds_cluster_instance" "cluster_instances_reader" { + apply_immediately = (known after apply) ~ arn = - -> (known after apply) ~ cluster_identifier = -> (known after apply) # forces replacement ~ dbi_resource_id = -> (known after apply) ~ endpoint = - -> (known after apply) ~ engine_version_actual = "8.0.mysql_aurora.3.02.2" -> (known after apply) ~ id = "database-1-aurora-reader" -> (known after apply) + identifier_prefix = (known after apply) + kms_key_id = (known after apply) + monitoring_role_arn = (known after apply) ~ network_type = "IPV4" -> (known after apply) ~ performance_insights_kms_key_id = - -> (known after apply) ~ port = 3306 -> (known after apply) ~ preferred_backup_window = "22:04-22:34" -> (known after apply) ~ preferred_maintenance_window = "mon:03:05-mon:03:35" -> (known after apply) ~ storage_encrypted = false -> (known after apply) - tags = {} -> null ~ tags_all = {} -> (known after apply) ~ writer = false -> (known after apply) # (15 unchanged attributes hidden) } # aws_rds_cluster_instance.cluster_instances_writer must be replaced -/+ resource "aws_rds_cluster_instance" "cluster_instances_writer" { + apply_immediately = (known after apply) ~ arn = - -> (known after apply) ~ cluster_identifier =-> (known after apply) # forces replacement ~ dbi_resource_id = -> (known after apply) ~ endpoint = -> (known after apply) ~ engine_version_actual = "8.0.mysql_aurora.3.02.2" -> (known after apply) ~ id = "database-1-aurora-writer" -> (known after apply) + identifier_prefix = (known after apply) + kms_key_id = (known after apply) + monitoring_role_arn = (known after apply) ~ network_type = "IPV4" -> (known after apply) ~ performance_insights_kms_key_id = - -> (known after apply) ~ port = 3306 -> (known after apply) ~ preferred_backup_window = "22:04-22:34" -> (known after apply) ~ preferred_maintenance_window = "thu:01:11-thu:01:41" -> (known after apply) ~ storage_encrypted = false -> (known after apply) - tags = {} -> null ~ tags_all = {} -> (known after apply) ~ writer = true -> (known after apply) # (15 unchanged attributes hidden) } # aws_route_table.privateRT will be updated in-place ~ resource "aws_route_table" "privateRT" { id = "rtb-0538dfe8b9d7f73d8" ~ route = [ - { - carrier_gateway_id = "" - cidr_block = "0.0.0.0/0" - core_network_arn = "" - destination_prefix_list_id = "" - egress_only_gateway_id = "" - gateway_id = "" - instance_id = "" - ipv6_cidr_block = "" - local_gateway_id = "" - nat_gateway_id = "nat-xxxxxxxxxxxxx" - network_interface_id = "" - transit_gateway_id = "" - vpc_endpoint_id = "" - vpc_peering_connection_id = "" }, + { + carrier_gateway_id = "" + cidr_block = "0.0.0.0/0" + core_network_arn = "" + destination_prefix_list_id = "" + egress_only_gateway_id = "" + gateway_id = "nat-xxxxxxxxxx" + instance_id = "" + ipv6_cidr_block = "" + local_gateway_id = "" + nat_gateway_id = "" + network_interface_id = "" + transit_gateway_id = "" + vpc_endpoint_id = "" + vpc_peering_connection_id = "" }, ] tags = { "Name" = "private-RT" } # (5 unchanged attributes hidden) } # aws_secretsmanager_secret.example will be created + resource "aws_secretsmanager_secret" "example" { + arn = (known after apply) + force_overwrite_replica_secret = false + id = (known after apply) + name = "aurora-rds-secret" + name_prefix = (known after apply) + policy = (known after apply) + recovery_window_in_days = 30 + rotation_enabled = (known after apply) + rotation_lambda_arn = (known after apply) + tags_all = (known after apply) } Plan: 4 to add, 1 to change, 3 to destroy.
原因分析
- 可用区配置不匹配:执行计划中
aws_rds_cluster的availability_zones字段标注了# forces replacement,当前集群实际使用的可用区包含eu-west-1c,但配置中引用的data.aws_availability_zones.available返回的可用区列表发生了变化,导致配置与实际状态不一致。Aurora集群的可用区列表属于不可更新属性,修改会直接触发销毁重建。 - 实例依赖集群重建:由于集群需要销毁重建,关联的
aws_rds_cluster_instance因cluster_identifier指向的集群资源被替换,必须同步销毁重建。 - 其他属性差异:执行计划中显示的
tags、backtrack_window等属性从实际值变为null,属于Terraform与AWS API的状态差异,但不会触发销毁重建,仅为次要因素。
解决办法
1. 固定可用区配置
直接在aws_rds_cluster中硬编码当前集群使用的可用区,避免数据源动态变化导致的差异:
availability_zones = ["eu-west-1a", "eu-west-1c"]
2. 忽略可用区变更
如果不需要修改可用区,在aws_rds_cluster的lifecycle块中添加availability_zones到忽略列表:
lifecycle { ignore_changes = [engine_version, availability_zones] }
这样Terraform会忽略可用区的配置与实际状态差异,不会触发销毁重建。
3. 调整数据源筛选条件
修改data.aws_availability_zones.available的筛选规则,确保返回的可用区与集群当前使用的一致:
data "aws_availability_zones" "available" { state = "available" filter { name = "zone-name" values = ["eu-west-1a", "eu-west-1c"] } }
4. 显式设置可选属性
对于backtrack_window、tags等属性,在配置中显式设置值(如backtrack_window = 0),避免Terraform认为属性需要变更。
内容的提问来源于stack exchange,提问作者Tayyab
相关产品推荐
相关产品推荐

