OpenTofuの外でRDSを入れ替える
概要
OpenTofuでリソースを作成しています。
RDSを特定の断面に戻するときに、スナップショットなどを利用して復旧をしますが、AWSのコンソール上などからは新しいDatabaseやClusterの作成となってしまいます。
復旧したDatabaseを前のDBと置き換えて利用したいというユースケースがあり、その際にOpenTofuでのリソースの差分が出るかを検証してみました。
結果
RDSの名称を入れ替えることで、OpenTofuでのリソースの差分は出ないようになりました。
ただし、内部的に一意のIDを持っているのか、外部でStateが変更されているよっていう警告が初回に出力されるようです。
なんで一意の名称を変えられるようになっているんでしょうね。不思議です。 → 内部的に DbiResourceId のIDを利用しているみたいですね。
詳細
前提条件
- OpenTofuを利用してAWSのリソースを管理しています
- 利用用途としては、ほぼTerraformと一緒なので、Terraformでも同様の動きになると思います(未検証)
- RDSを利用しており、特定のユースケースにおいて、DBを特定の断面に戻す場合があります
- RDSの機能としてPITRなどを利用することによって、特定の断面に戻すことは簡単ですが、新しいDatabaseを作成する必要があります
- 通常はこの利用方法で問題ないのですが、アプリケーション側の接続先の修正や、OpenTofuのstateの管理外になってしまうなど、色々と面倒が多いです
- そこで、もともとのDBと同じ接続情報や名称を持つように守勢することで、上記のような修正が発生しないようにできないかを検討しました
RDSの修正について
- AWSのリソースは一意なID的なものが割り振られており、一度作成すると変更できない場合がほとんどです。
- EC2のAMI IDなど
- RDSはなぜだかわかりませんが、ARNでも利用しているDatabaseの名前を変更することができます
試しにコンソールで名前を変更してみたキャプチャです

詳細
OpenTofuで同じStateだと認識されるために以下の手順でバックアップを起動して、復元を行います
- 対象のDatabase(元DB)のスナップショットより、Databaseを作成する(復元DB)
- この時、パラメータなどは既存のDatabaseと極力同じになるようにする
- 元DBの名称を変える。
- 復元DBの名称を元DBと同じ名称にする
- OpenTofuのplanを実行して、差分が出ないことを確認する
上記の実行シェル
上記の実行を試すにあたって、CLIで作成したものがあるので、共有します
restore-db-instance-from-db-snapshot という便利なコマンドがあったのですが、元の情報を持っていない部分も多いので注意が必要です。
#!/usr/bin/env bash
set -euo pipefail
wait_instance_available() {
local identifier="$1"
echo "[INFO] ${identifier} が利用可能になるまで待機します..."
# インスタンスが認識されるまでリトライ
until aws rds describe-db-instances --db-instance-identifier "${identifier}" >/dev/null 2>&1; do
sleep 15
done
# available になるまで公式 waiter を利用
aws rds wait db-instance-available --db-instance-identifier "${identifier}"
echo "[INFO] ${identifier} が利用可能になりました。"
}
read -p "復元元のRDSインスタンス名を入力してください: " SOURCE_INSTANCE
read -p "使用するスナップショット識別子(DB Snapshot ID)を入力してください: " SNAPSHOT_ID
DB_INFO=$(aws rds describe-db-instances --db-instance-identifier $SOURCE_INSTANCE | jq -r '.DBInstances[0]')
DB_INSTANCE_CLASS=$(echo $DB_INFO | jq -r '.DBInstanceClass')
DB_SUBNET_GROUP_NAME=$(echo $DB_INFO | jq -r '.DBSubnetGroup.DBSubnetGroupName')
VPC_SECURITY_GROUP_IDS=$(echo $DB_INFO | jq -r '.VpcSecurityGroups[0].VpcSecurityGroupId')
DB_PARAMETER_GROUP_NAME=$(echo $DB_INFO | jq -r '.DBParameterGroups[0].DBParameterGroupName')
echo "\n=== ステップ 1: スナップショットから ${TARGET_INSTANCE} を作成 ==="
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier "${TARGET_INSTANCE}" \
--db-snapshot-identifier "${SNAPSHOT_ID}" \
--db-instance-class $DB_INSTANCE_CLASS \
--db-subnet-group-name $DB_SUBNET_GROUP_NAME \
--vpc-security-group-ids $VPC_SECURITY_GROUP_IDS \
--db-parameter-group-name $DB_PARAMETER_GROUP_NAME \
--no-publicly-accessible
wait_instance_available "${TARGET_INSTANCE}"
echo "\n=== ステップ 2: 元インスタンス ${SOURCE_INSTANCE} を ${ORIGINAL_INSTANCE} にリネーム ==="
aws rds modify-db-instance \
--db-instance-identifier "${SOURCE_INSTANCE}" \
--new-db-instance-identifier "${ORIGINAL_INSTANCE}" \
--apply-immediately
wait_instance_available "${ORIGINAL_INSTANCE}"
echo "\n=== ステップ 3: リストアしたインスタンス ${TARGET_INSTANCE} を ${SOURCE_INSTANCE} にリネーム ==="
aws rds modify-db-instance \
--db-instance-identifier "${TARGET_INSTANCE}" \
--new-db-instance-identifier "${SOURCE_INSTANCE}" \
--apply-immediately
wait_instance_available "${SOURCE_INSTANCE}"
echo "\n[INFO] リストアとリネーム処理完了"
echo " 旧環境: ${ORIGINAL_INSTANCE}"
echo " 新環境: ${SOURCE_INSTANCE}"
OpenTofuの実行結果
適当に作成したリポジトリを利用しつつリソースの作成、スナップショットの作成、名称変更を実行してみました。
まずはリソースを作成します
cd environments/dev
tofu init
tofu apply
コンソールでスナップショットを作成後、上記で作成したシェルを利用して名称の変更を行います
bash restore.sh
復元DBが元DBの名前で作成されているので、planしたときの挙動を確認します
# リソースを変更したいわけではないので、planにしています
tofu plan
結果は、内部的にIDを保持しているらしく、元DBの名称が変更になったと検知されます。
→ Geminiに聞いてみたところ、内部的に DbiResourceId のIDを利用しているみたいで、それの値を優先して差分を取得しているようです
OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
OpenTofu will perform the following actions:
# module.main.module.database.aws_db_instance.this will be updated in-place
~ resource "aws_db_instance" "this" {
id = "db-CZAQAIMYN4YIRBFGBRKINGLCMA"
~ identifier = "opentofu-aws-sample-dev-exampledb-original" -> "opentofu-aws-sample-dev-exampledb"
tags = {
"Name" = "opentofu-aws-sample-dev-exampledb"
}
# (56 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
なので、元DBをコンソールから削除して再度実行すると結果が変ります。
No changes. Your infrastructure matches the configuration.
OpenTofu has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
意図した通り、OpenTofu上では差分がない状態になりました。
結論
OpenTofuの外でRDSの名称の変更を行い、別のRDSに入れ替えたとしても、パラメータグループなどの設定が同じである場合はterraform planの結果は差分なしとすることができました。
ただし、何かしら内部で持っている値があるらしく、入れ替え元のDatabaseを削除しないと正しく認識されないことも分かりました。
Discussion