本記事はAsiaQuest Advent Calendarの21日目です。
クラウドインテグレーション部の渡邊です。
今回は、Terraformを利用して、RDS(Amazon Aurora MySQL)のメジャーバージョンをアップグレードする際にハマったことと、その対処について説明します。
今回使用した初期コードはこちらです。
ネットワークリソース等は、既存環境の値を用いる想定でコードを作成しました。
variableは省略しているため、ご自身の環境に合ったものをご用意ください。
provider "aws" {
region = "ap-northeast-1"
}
terraform {
required_version = "~> 1.2.0"
backend "s3" {
bucket = "test-bucket"
key = "actions/rds/terraform.tfstate"
region = "ap-northeast-1"
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.64.0"
}
}
}
resource "aws_db_subnet_group" "db-subgp" {
name = "test-dbsg"
subnet_ids = [
var.subnet-1a,
var.subnet-1c
]
}
resource "aws_rds_cluster_parameter_group" "dbcpg" {
name = "test-dbcpg"
family = "aurora-mysql5.7"
description = "cluster parameter group"
}
resource "aws_rds_cluster" "db" {
cluster_identifier = "test-db-cluster"
db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.dbcpg.name
db_subnet_group_name = aws_db_subnet_group.db-subgp.name
vpc_security_group_ids = [var.sg]
engine_mode = "provisioned"
master_username = "admin"
master_password = "Passw0rd!"
engine = "aurora-mysql"
engine_version = "5.7.mysql_aurora.2.12.0"
port = 3306
final_snapshot_identifier = "temp"
}
resource "aws_rds_cluster_instance" "db-instance" {
identifier = "test-db-instance-01"
cluster_identifier = aws_rds_cluster.db.id
instance_class = "db.t3.small"
engine = aws_rds_cluster.db.engine
engine_version = aws_rds_cluster.db.engine_version
ca_cert_identifier = "rds-ca-rsa2048-g1"
}
メジャーバージョンをアップグレードするために、少なくとも、本構成では以下のパラメータを変更する必要があります。
これらを変更してterraform applyコマンドを実行して、設定変更を適用したところ、エラーが発生しました。
$ terraform apply
aws_rds_cluster_parameter_group.dbcpg: Refreshing state... [id=test-dbcpg]
aws_db_subnet_group.db-subgp: Refreshing state... [id=test-dbsg]
aws_rds_cluster.db: Refreshing state... [id=test-db-cluster]
aws_rds_cluster_instance.db-instance: Refreshing state... [id=test-db-instance-01]
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
Terraform will perform the following actions:
# aws_rds_cluster.db will be updated in-place
~ resource "aws_rds_cluster" "db" {
~ engine_version = "5.7.mysql_aurora.2.12.0" -> "8.0.mysql_aurora.3.05.0"
id = "test-db-cluster"
tags = {}
# (36 unchanged attributes hidden)
}
# aws_rds_cluster_instance.db-instance will be updated in-place
~ resource "aws_rds_cluster_instance" "db-instance" {
~ engine_version = "5.7.mysql_aurora.2.12.0" -> "8.0.mysql_aurora.3.05.0"
id = "test-db-instance-01"
tags = {}
# (26 unchanged attributes hidden)
}
# aws_rds_cluster_parameter_group.dbcpg must be replaced
-/+ resource "aws_rds_cluster_parameter_group" "dbcpg" {
~ arn = "arn:aws:rds:ap-northeast-1:315408206347:cluster-pg:test-dbcpg" -> (known after apply)
~ family = "aurora-mysql5.7" -> "aurora-mysql8.0" # forces replacement
~ id = "test-dbcpg" -> (known after apply)
name = "test-dbcpg"
+ name_prefix = (known after apply)
- tags = {} -> null
~ tags_all = {} -> (known after apply)
# (1 unchanged attribute hidden)
}
Plan: 1 to add, 2 to change, 1 to destroy.
aws_rds_cluster_parameter_group.dbcpg: Destroying... [id=test-dbcpg]
aws_rds_cluster_parameter_group.dbcpg: Still destroying... [id=test-dbcpg, 10s elapsed]
aws_rds_cluster_parameter_group.dbcpg: Still destroying... [id=test-dbcpg, 20s elapsed]
略
aws_rds_cluster_parameter_group.dbcpg: Still destroying... [id=test-dbcpg, 2m50s elapsed]
╷
│ Error: deleting RDS Cluster Parameter Group (test-dbcpg): operation error RDS: DeleteDBClusterParameterGroup, https response error StatusCode: 400, RequestID: d851f851-9ed1-4da7-a322-a1637a468a80, InvalidDBParameterGroupState: One or more database instances are still members of this parameter group test-dbcpg, so the group cannot be deleted
│
│
╵
aws_rds_cluster_parameter_groupのreplaceによってdestroyの実行を試みますが、DBがデフォルトのクラスタパラメータグループ(以降、CPGと呼ぶ)に関連付けられているため、エラーが発生しました。
By default, when Terraform must change a resource argument that cannot be updated in-place due to remote API limitations, Terraform will instead destroy the existing object and then create a new replacement object with the new configured arguments.
引用元:The lifecycle Meta-Argument
depends_on = [ aws_rds_cluster.db , aws_rds_cluster_instance.db-instance ]
lifecycle {
create_before_destroy = true
}
╷
│ Error: creating DB Cluster Parameter Group (test-dbcpg): DBParameterGroupAlreadyExists: Parameter group test-dbcpg already exists
│ status code: 400, request id: 3f62eb3b-a4b8-4186-8fbb-da2a02ccb29a
│
│ with aws_rds_cluster_parameter_group.dbcpg,
│ on main.tf line 37, in resource "aws_rds_cluster_parameter_group" "dbcpg":
│ 37: resource "aws_rds_cluster_parameter_group" "dbcpg" {
│
╵
以上の対応でも難しいことから、手動で正しくメジャーバージョンアップグレードができるように、適切な順番で設定変更して対処する方針となりました。
なお、今回はCPGのみカスタムし、インスタンスパラメータグループはデフォルトを使用しております。
よって、パラメータグループの設定変更はCPGのみを対象としております。
設定適用の流れは以下の通りです。
① 1回目の適用
② 2回目の適用
③ 3回目の適用
メジャーバージョンアップグレードを許可するパラメータallow_major_version_upgradeをtrueにする
allow_major_version_upgradeをtrueにしないと、メジャーバージョンアップグレードに失敗するので、事前に設定しておきます。
デフォルトでfalseであるため注意しましょう。
デフォルトのCPG(default.aurora-mysql X.X)へ関連付ける
カスタムCPGおよびエンジンバージョンをアップグレードするために、デフォルトのCPGに関連付けた後、もともとアタッチしていたCPGのバージョンを変更する方針とします。
設定変更を即時反映するパラメータapply_immediatelyをtrueにする
設定変更を即時反映するために、インスタンスおよびクラスタにパラメータapply_immediatelyを追加します。
インスタンス、およびクラスタのapply_immediatelyのデフォルト値はfalseなので注意しましょう。
1回目の適用による変更後のコードは以下です。
resource "aws_rds_cluster" "db" {
cluster_identifier = "test-db-cluster"
- db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.dbcpg.name
+ db_cluster_parameter_group_name = "default.aurora-mysql5.7"
db_subnet_group_name = aws_db_subnet_group.db-subgp.name
vpc_security_group_ids = [var.sg]
engine_mode = "provisioned"
master_username = "admin"
master_password = "Passw0rd!"
engine = "aurora-mysql"
engine_version = "5.7.mysql_aurora.2.12.0"
+ allow_major_version_upgrade = true
port = 3306
final_snapshot_identifier = "temp"
+ apply_immediately = true
}
resource "aws_rds_cluster_instance" "db-instance" {
identifier = "test-db-instance-01"
cluster_identifier = aws_rds_cluster.db.id
instance_class = "db.t3.small"
engine = aws_rds_cluster.db.engine
engine_version = aws_rds_cluster.db.engine_version
ca_cert_identifier = "rds-ca-rsa2048-g1"
+ apply_immediately = true
}
terraform applyコマンドで設定変更の適用に成功しました。
$ terraform apply
略
Terraform will perform the following actions:
# aws_rds_cluster.db will be updated in-place
~ resource "aws_rds_cluster" "db" {
~ allow_major_version_upgrade = false -> true
~ db_cluster_parameter_group_name = "test-dbcpg" -> "default.aurora-mysql5.7"
+ apply_immediately = true
id = "test-db-cluster"
tags = {}
# (36 unchanged attributes hidden)
}
# aws_rds_cluster_instance.db-instance will be updated in-place
~ resource "aws_rds_cluster_instance" "db-instance" {
+ apply_immediately = true
id = "test-db-instance-01"
tags = {}
# (26 unchanged attributes hidden)
}
Plan: 0 to add, 2 to change, 0 to destroy.
略
Apply complete! Resources: 0 added, 2 changed, 0 destroyed.
resource "aws_rds_cluster_parameter_group" "dbcpg" {
name = "test-dbcpg"
- family = "aurora-mysql5.7"
+ family = "aurora-mysql8.0"
description = "cluster parameter group"
}
╷
│ Error: updating RDS Cluster (test-db-cluster): InvalidDBInstanceState: Cannot modify engine version because there is a pending orderable config change for DB instance: test-db-instance-01
│ status code: 400, request id: 9618c4fc-b42e-405e-8d91-0645d04b23bc
│
│ with aws_rds_cluster.db,
│ on main.tf line 44, in resource "aws_rds_cluster" "db":
│ 44: resource "aws_rds_cluster" "db" {
│
╵
サポートしているインスタンスクラスは以下のように確認できます。
こちらは8.0.mysql_aurora.3.05.0のサポートするインスタンスクラスを表示します。
aws rds describe-orderable-db-instance-options \
--engine aurora-mysql \
--query 'OrderableDBInstanceOptions[].[DBInstanceClass,StorageType,Engine,EngineVersion]' \
--output table \
--region ap-northeast-1 \
| grep 8.0.mysql_aurora.3.05.0
以下のように、インスタンスクラスinstance_classを変更します。
resource "aws_rds_cluster_instance" "db-instance" {
identifier = "test-db-instance-01"
cluster_identifier = aws_rds_cluster.db.id
- instance_class = "db.t3.small"
+ instance_class = "db.t4g.medium"
engine = aws_rds_cluster.db.engine
engine_version = aws_rds_cluster.db.engine_version
ca_cert_identifier = "rds-ca-rsa2048-g1"
apply_immediately = true
}
即時反映も含めた設定を適用することで、後続の作業もエラーにならないはずです。
$ terraform apply
略
Terraform will perform the following actions:
# aws_rds_cluster.db will be updated in-place
~ resource "aws_rds_cluster" "db" {
id = "test-db-cluster"
tags = {}
# (38 unchanged attributes hidden)
}
# aws_rds_cluster_instance.db-instance will be updated in-place
~ resource "aws_rds_cluster_instance" "db-instance" {
id = "test-db-instance-01"
~ instance_class = "db.t3.small" -> "db.t4g.medium"
tags = {}
# (26 unchanged attributes hidden)
}
Plan: 0 to add, 2 to change, 0 to destroy.
略
Apply complete! Resources: 0 added, 2 changed, 0 destroyed.
また、インスタンスクラスとメジャーバージョンアップグレードを同時に行おうとすると、メジャーバージョンアップグレード後のエンジンバージョンと、現在のインスタンスクラスの組み合わせが正しくない旨のエラーがでます。
そのため、まずインスタンスクラスの変更完了後、メジャーバージョンアップグレードを試みる必要があります。
╷
│ Error: updating RDS Cluster (test-db-cluster): InvalidParameterCombination: RDS does not support creating a DB instance with the following combination: DBInstanceClass=db.t3.small, Engine=aurora-mysql, EngineVersion=8.0.mysql_aurora.3.05.0, LicenseModel=general-public-license. For supported combinations of instance class and database engine version, see the documentation.
│ status code: 400, request id: da1645b8-8bfd-4b23-a31f-5530fbe9bacd
│
│ with aws_rds_cluster.db,
│ on main.tf line 44, in resource "aws_rds_cluster" "db":
│ 44: resource "aws_rds_cluster" "db" {
│
╵
以上を踏まえて、変更したコードは以下のようになります。
resource "aws_rds_cluster_parameter_group" "dbcpg" {
name = "test-dbcpg"
family = "aurora-mysql8.0"
description = "cluster parameter group"
}
resource "aws_rds_cluster" "db" {
cluster_identifier = "test-db-cluster"
db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.dbcpg.name
db_subnet_group_name = aws_db_subnet_group.db-subgp.name
vpc_security_group_ids = [var.sg]
engine_mode = "provisioned"
master_username = "admin"
master_password = "Passw0rd!"
engine = "aurora-mysql"
engine_version = "8.0.mysql_aurora.3.05.0"
allow_major_version_upgrade = true
port = 3306
final_snapshot_identifier = "temp"
apply_immediately = true
}
resource "aws_rds_cluster_instance" "db-instance" {
identifier = "test-db-instance-01"
cluster_identifier = aws_rds_cluster.db.id
# instance_class = "db.t3.small"
instance_class = "db.t4g.medium"
engine = aws_rds_cluster.db.engine
engine_version = aws_rds_cluster.db.engine_version
ca_cert_identifier = "rds-ca-rsa2048-g1"
apply_immediately = true
}
適用すると、成功しました。
$ terraform apply
略
# aws_rds_cluster.db will be updated in-place
~ resource "aws_rds_cluster" "db" {
~ db_cluster_parameter_group_name = "default.aurora-mysql5.7" -> "test-dbcpg"
~ engine_version = "5.7.mysql_aurora.2.12.0" -> "8.0.mysql_aurora.3.05.0"
id = "test-db-cluster"
tags = {}
# (37 unchanged attributes hidden)
}
# aws_rds_cluster_instance.db-instance will be updated in-place
~ resource "aws_rds_cluster_instance" "db-instance" {
~ engine_version = "5.7.mysql_aurora.2.12.0" -> "8.0.mysql_aurora.3.05.0"
id = "test-db-instance-01"
tags = {}
# (27 unchanged attributes hidden)
}
Plan: 0 to add, 2 to change, 0 to destroy.
略
Apply complete! Resources: 0 added, 2 changed, 0 destroyed.
コンソール画面およびTerraform側から確認すると、設定変更が問題なく行われていることがわかります。
$ terraform apply
aws_rds_cluster_parameter_group.dbcpg: Refreshing state... [id=test-dbcpg]
aws_db_subnet_group.db-subgp: Refreshing state... [id=test-dbsg]
aws_rds_cluster.db: Refreshing state... [id=test-db-cluster]
aws_rds_cluster_instance.db-instance: Refreshing state... [id=test-db-instance-01]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
【参考】