Terraform 在升级时会破坏 RDS 集群内的实例

Posted

技术标签:

【中文标题】Terraform 在升级时会破坏 RDS 集群内的实例【英文标题】:Terraform destroys the instance inside RDS cluster when upgrading 【发布时间】:2021-12-15 03:59:15 【问题描述】:

我使用 terraform 创建了一个包含 2 个实例的 RDS 集群。当我从前端升级 RDS 时,它会修改集群。但是当我使用 terraform 执行相同操作时,它会破坏实例。

我们尝试了 create_before_destroy,但它给出了错误。

我们尝试使用 ignore_changes=engine,但没有做出任何改变。

有什么办法可以预防吗?

resource "aws_rds_cluster" "rds_mysql" 
  cluster_identifier              = var.cluster_identifier
  engine                          = var.engine
  engine_version                  = var.engine_version
  engine_mode                     = var.engine_mode
  availability_zones              = var.availability_zones
  database_name                   = var.database_name
  port                            = var.db_port
  master_username                 = var.master_username
  master_password                 = var.master_password
  backup_retention_period         = var.backup_retention_period
  preferred_backup_window         = var.engine_mode == "serverless" ? null : var.preferred_backup_window
  db_subnet_group_name            = var.create_db_subnet_group == "true" ? aws_db_subnet_group.rds_subnet_group[0].id : var.db_subnet_group_name
  vpc_security_group_ids          = var.vpc_security_group_ids
  db_cluster_parameter_group_name = var.create_cluster_parameter_group == "true" ? aws_rds_cluster_parameter_group.rds_cluster_parameter_group[0].id : var.cluster_parameter_group
  skip_final_snapshot             = var.skip_final_snapshot
  deletion_protection             = var.deletion_protection
  allow_major_version_upgrade     = var.allow_major_version_upgrade
  lifecycle 
    create_before_destroy = false
    ignore_changes        = [availability_zones]
  


resource "aws_rds_cluster_instance" "cluster_instances" 
  count                      = var.engine_mode == "serverless" ? 0 : var.cluster_instance_count
  identifier                 = "$var.cluster_identifier-$count.index"
  cluster_identifier         = aws_rds_cluster.rds_mysql.id
  instance_class             = var.instance_class
  engine                     = var.engine
  engine_version             = aws_rds_cluster.rds_mysql.engine_version
  db_subnet_group_name       = var.create_db_subnet_group == "true" ? aws_db_subnet_group.rds_subnet_group[0].id : var.db_subnet_group_name
  db_parameter_group_name    = var.create_db_parameter_group == "true" ? aws_db_parameter_group.rds_instance_parameter_group[0].id : var.db_parameter_group
  apply_immediately          = var.apply_immediately
  auto_minor_version_upgrade = var.auto_minor_version_upgrade
  lifecycle 
    create_before_destroy = false
    ignore_changes        = [engine_version]
  


错误:

resource \"aws_rds_cluster_instance\" \"cluster_instances\" \n\n\n\nError: error creating RDS Cluster (aurora-cluster-mysql) Instance: DBInstanceAlreadyExists: DB instance already exists\n\tstatus code: 400, request id: c6a063cc-4ffd-4710-aff2-eb0667b0774f\n\n on 

计划输出:

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place
+/- create replacement and then destroy

Terraform will perform the following actions:

  # module.rds_aurora_create[0].aws_rds_cluster.rds_mysql will be updated in-place
  ~ resource "aws_rds_cluster" "rds_mysql" 
      ~ allow_major_version_upgrade         = false -> true
      ~ engine_version                      = "5.7.mysql_aurora.2.07.1" -> "5.7.mysql_aurora.2.08.1"
        id                                  = "aurora-cluster-mysql"
        tags                                = 
        # (33 unchanged attributes hidden)
    

  # module.rds_aurora_create[0].aws_rds_cluster_instance.cluster_instances[0] must be replaced
+/- resource "aws_rds_cluster_instance" "cluster_instances" 
      ~ arn                             = "arn:aws:rds:us-east-1:account:db:aurora-cluster-mysql-0" -> (known after apply)
      ~ availability_zone               = "us-east-1a" -> (known after apply)
      ~ ca_cert_identifier              = "rds-ca-" -> (known after apply)
      ~ dbi_resource_id                 = "db-32432432SDF" -> (known after apply)
      ~ endpoint                        = "aurora-cluster-mysql-0.jkjk.us-east-1.rds.amazonaws.com" -> (known after apply)
      ~ engine_version                  = "5.7.mysql_aurora.2.07.1" -> "5.7.mysql_aurora.2.08.1" # forces replacement
      ~ id                              = "aurora-cluster-mysql-0" -> (known after apply)
      + identifier_prefix               = (known after apply)
      + kms_key_id                      = (known after apply)
      + monitoring_role_arn             = (known after apply)
      ~ performance_insights_enabled    = false -> (known after apply)
      + performance_insights_kms_key_id = (known after apply)
      ~ port                            = 3306 -> (known after apply)
      ~ preferred_backup_window         = "07:00-09:00" -> (known after apply)
      ~ preferred_maintenance_window    = "thu:06:12-thu:06:42" -> (known after apply)
      ~ storage_encrypted               = false -> (known after apply)
      - tags                            =  -> null
      ~ tags_all                        =  -> (known after apply)
      ~ writer                          = true -> (known after apply)
        # (12 unchanged attributes hidden)
    

Plan: 1 to add, 1 to change, 1 to destroy.

【问题讨论】:

在哪个版本和哪个版本之间?请在您的确切 TF 配置中添加一些关于集群和实例的代码 + 完整的 terraform plan 输出。 【参考方案1】:

我看到 aws_rds_cluster 资源中没有 apply_immediately 参数,你可以添加它并尝试。

【讨论】:

【参考方案2】:

Terraform 发现实例上的引擎版本发生变化,并将其检测为强制替换的操作。

删除(或忽略对engine_version 输入的更改)aws_rds_cluster_instance 资源。

当您升级集群的引擎版本时,AWS RDS 会升级集群实例的引擎版本本身(这就是您可以通过 AWS 控制台进行就地升级的原因)。

通过排除 engine_version 输入,Terraform 将不会看到对 aws_rds_cluster_instances 所做的任何更改,并且不会执行任何操作。

AWS 将在内部处理实例的引擎升级。


如果您决定忽略更改,请在 lifecycle 块中使用 ignore_changes 参数:

resource "aws_rds_cluster_instance" "cluster_instance" 
  engine_version     = aws_rds_cluster.main.engine_version
  ...

  lifecycle 
    ignore_changes        = [engine_version]
  

【讨论】:

我们试过了。该代码正在创建新的 DBInstance 并失败,而不是修改它们。我在上面的问题中添加了代码和错误。 这里有任何更新,我正在寻找相同的答案 @MayaRay 啊,您的 Q 缺少代码 - 您能否将 terraform plan 的确切输出添加到问题中?然后我可以建议 添加了计划输出。请检查。 @MayaRay 删除引擎版本能完全解决这个问题吗?另外,您使用的是什么 Terraform 版本?【参考方案3】:

我不知道,但经过一些谷歌搜索后,我发现了这个: https://github.com/hashicorp/terraform-provider-aws/issues/10714

即向 AWS Terraform 提供商报告错误:

当 apply_immediately 设置为 false 时更新 engine_version 时,resource/aws_rds_cluster_instance 被销毁并重新创建

这似乎与您面临的问题完全相同。

那里的一条评论似乎指向了一个解决方案:

从提供程序的 v3.63.0 (EDITED) 开始,对 aws_rds_cluster_instance 资源的 engine_version 参数的更新不再强制替换资源。

原始评论似乎有错字 - 3.36 vs. 3.63。

您可以尝试升级您的aws Terraform 提供程序吗?

【讨论】:

我们尝试使用 terraform 版本 14.8 和 aws provider 版本 3.63 。它说修改完成,但它没有在控制台中进行任何更改。 好像是对供应商团队的反馈?

以上是关于Terraform 在升级时会破坏 RDS 集群内的实例的主要内容,如果未能解决你的问题,请参考以下文章

Terraform,AWS RDS aurora mysql serverless 异常“找不到源集群”

在 AWS RDS 集群实例上使用 Terraform 预置多个逻辑数据库

Terraform - 在可用时使用 rds 快照

在 terraform 失败的不同 vpc 中创建时出现 rds 副本错误

使用 Terraform 创建 AWS MySQL RDS 实例时出错

需要通过 Terraform 在 AWS RDS 中启用备份复制功能