[Terraform] RDS DB インスタンスに対して AWS Backup の継続的バックアップ(PITR)を取得したら plan に差分が出たので調べてみた

2022.09.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは、アノテーション構築チームの荒川です。

先日、Terraform で RDS DB インスタンスを作成し、AWS Backup の継続的バックアップ(PITR)対象に追加しました。しばらくした後、RDS DB インスタンスで再度 terraform plan を行った際に、変更を行っていないにもかかわらずバックアップ保持期間の値に差分が出ました。

そこで調べた過程と対策をまとめます。

環境情報

$ terraform -v
Terraform v1.3.0
on darwin_arm64
+ provider registry.terraform.io/hashicorp/aws v4.32.0
+ provider registry.terraform.io/hashicorp/random v3.4.3

今回の検証用コード

GitHub へアップロードしてますので、気になる方は見てみてください。

RDS DB インスタンス自動バックアップの概要

マネジメントコンソールでは RDS DB インスタンス作成時に「自動バックアップを有効にします」のチェックボックスにチェックをすると「バックアップ保持期間」が表示されます。日数を 1 以上に指定することで自動バックアップが実現できます。

バックアップの使用 - Amazon Relational Database Service

バックアップ保持期間は、0 ~ 35 日間で設定できます。バックアップ保持期間を 0 に設定すると、自動バックアップが無効になります。

同様に Terraform のリソース aws_db_instance で自動バックアップを行う場合、有効化/無効化の指定はなく、backup_retention_period に 1 以上の値を指定するだけで実現できます。
今回、バックアップは AWS Backup で一元管理したかったので、DB インスタンスの属性 backup_retention_period へ明示的に 0(無効) を指定しました。

AWS Backup でのバックアップ一元管理

上述の状態で AWS Backup のバックアップ保持期間を指定すると、設定後最初の自動バックアップが取得されるまでは差分が出ません。

リソース作成直後

$ terraform plan
random_password.example: Refreshing state... [id=none]
aws_backup_vault.example: Refreshing state... [id=example_backup_vault]
aws_db_parameter_group.example: Refreshing state... [id=mysql-8-0-parameter-group]
aws_db_subnet_group.example: Refreshing state... [id=blog-db-subnet-group]
aws_backup_plan.example: Refreshing state... [id=2ebfd8b1-10b6-4280-9e03-52cb55345fc6]
aws_db_instance.example: Refreshing state... [id=terraform-20220927061250979500000001]
aws_backup_selection.example: Refreshing state... [id=39282263-da6b-463c-9826-663870d5aaa6]

No changes. Your infrastructure matches the configuration.
$ aws rds describe-db-instances \
    | jq '.DBInstances[].BackupRetentionPeriod'
0

AWS Backup で自動バックアップが一度でも取得されると、以降は RDS DB インスタンスで設定した 0 と AWS Backup のバックアップ保持期間で差分が出るようになります。ちなみに、オンデマンドバックアップでは差分が出ませんでした。

最初の自動バックアップ取得完了まで待った後

$ terraform plan
random_password.example: Refreshing state... [id=none]
aws_db_parameter_group.example: Refreshing state... [id=mysql-8-0-parameter-group]
aws_backup_vault.example: Refreshing state... [id=tf_example_backup_vault]
aws_db_subnet_group.example: Refreshing state... [id=blog-db-subnet-group]
aws_backup_plan.example: Refreshing state... [id=2ebfd8b1-10b6-4280-9e03-52cb55345fc6]
aws_db_instance.example: Refreshing state... [id=terraform-20220927061250979500000001]
aws_backup_selection.example: Refreshing state... [id=39282263-da6b-463c-9826-663870d5aaa6]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_db_instance.example will be updated in-place
  ~ resource "aws_db_instance" "example" {
      ~ backup_retention_period               = 14 -> 0
        id                                    = "terraform-20220927061250979500000001"
        name                                  = "mydb"
        tags                                  = {}
        # (59 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.
$ aws rds describe-db-instances \
    | jq '.DBInstances[].BackupRetentionPeriod'
14

RDS コンソールの変更画面から自動バックアップを確認すると、「バックアッププランが存在する」と表示され、バックアッププランを参照するよう促されます。

apply 直後は plan に差分がありませんが、しばらくすると差分が出てくる困った挙動です。

対策

backup_retention_period = 0 の行をコメントアウトするか、backup_retention_period = null とすると差分が消えます。

main.tf

# RDS for MySQL DB インスタンス
resource "aws_db_instance" "example" {
  allocated_storage    = 10
  db_name              = "mydb"
  engine               = "mysql"
  engine_version       = "8.0.28"
  instance_class       = "db.t3.micro"
  db_subnet_group_name = aws_db_subnet_group.example.name
  username             = "foo"
  password             = random_password.example.result
  parameter_group_name = aws_db_parameter_group.example.name
  skip_final_snapshot  = true

  ##############
  # 差分が出る例 #
  ##############
  // AWS Backup で取得するため RDS の自動バックアップは無効にする
  # backup_retention_period = 0

  ################
  # 差分が出ない例 #
  ################
  // backup_retention_period を書かない、もしくは null を指定する
  backup_retention_period = null
}

上記の「差分が出ない例」へ修正後、再度 plan を実行すると差分が消えます。

$ terraform plan
random_password.example: Refreshing state... [id=none]
aws_db_parameter_group.example: Refreshing state... [id=mysql-8-0-parameter-group]
aws_backup_vault.example: Refreshing state... [id=tf_example_backup_vault]
aws_db_subnet_group.example: Refreshing state... [id=blog-db-subnet-group]
aws_db_instance.example: Refreshing state... [id=terraform-20220927061250979500000001]
aws_backup_plan.example: Refreshing state... [id=2ebfd8b1-10b6-4280-9e03-52cb55345fc6]
aws_backup_selection.example: Refreshing state... [id=39282263-da6b-463c-9826-663870d5aaa6]

No changes. Your infrastructure matches the configuration.

まとめ

以下の条件をすべて満たすと、既存 Terraform 管理のリソース aws_db_instance の plan に差分が生じます。

  • Terraform で backup_retention_period = 0(自動バックアップ無効)の aws_db_instance を作成
  • AWS Backup で enable_continuous_backup = true(継続的バックアップ、RDS の自動バックアップ PITR 相当)を有効にしたプランで対象の DB インスタンスのバックアップを 1 回以上取得

この状態では RDS コンソールから DB インスタンスの変更から自動バックアップ設定を変更できず、AWS Backup プランへのコンソールリンクが表示されます。

なお、バックアッププランのルールで保持期間を変更しても、即座に RDS DB インスタンスのバックアップ保持期間へは反映されませんでした。1 日経っても変わっていなかったので、保持期間を確認したい場合は AWS Backup 側で参照してください。

保持期間 14 日 → 7 日へ変更して 24 時間待った後

aws rds describe-db-instances \
    | jq '.DBInstances[].BackupRetentionPeriod'
14

おわりに

バックアップは AWS Backup で一元管理したいという気持ちで、DB インスタンスの属性で backup_retention_period = 0 を指定したことから発生した事象でした。

この事象に遭遇した時、私の推測では RDS DB インスタンスのバックアップ保持期間が AWS Backup の保持期間の値を参照するようになったと考えていました。ただ、すぐに保持期間が反映されなかったことから、値の参照ではないことが確かめられました。

同じ事象に遭遇する方はあまりいないと思いますが、折角調べたのでブログにまとめました。どなたかのご参考になれば幸いです。

参考

アノテーション株式会社について

アノテーション株式会社は、クラスメソッド社のグループ企業として「オペレーション・エクセレンス」を担える企業を目指してチャレンジを続けています。「らしく働く、らしく生きる」のスローガンを掲げ、さまざまな背景をもつ多様なメンバーが自由度の高い働き方を通してお客様へサービスを提供し続けてきました。現在当社では一緒に会社を盛り上げていただけるメンバーを募集中です。少しでもご興味あれば、アノテーション株式会社WEBサイトをご覧ください。