RDS スナップショットから注文を復元する

AWSBeginner
オンラインで実践に進む

はじめに

誤ったデータ変更によって、アプリケーションが動作していても業務レコードが欠落することがあります。手動の RDS スナップショットを作成し、意図的な削除を実行してから、新しいインスタンスの復元とエンドポイントの切り替えで失われた注文を回復します。

先にデータベースと SQL の実習を完了してください。この独立した環境には、3 件のサンプル注文を持つプライマリと接続済みのアプリケーションがあります。回復を確認した後、2 つの練習用インスタンスとスナップショットを削除します。

認定試験との関連

この実習では、次の試験トピックに関する入門的な操作を練習します。

手動のデータベーススナップショットを作成する

このステップでは、変更前に現在のデータを保存します。

DB スナップショットは RDS インスタンスの回復用コピーです。手動スナップショットは明示的に作成し、削除するまで独立したリソースとして残ります。この実習では手動スナップショットを 1 つ使い、自動バックアップの保持やポイントインタイムリカバリは設定しません。

用意された接続設定を読み込み、アプリケーションデータを確認します。

cd /home/labex/project
source database.env
curl \
  --silent \
  --show-error \
  --fail \
  http://127.0.0.1:8080/application/orders | jq

注文 101、102、103 が表示されます。101 は Maya の注文で、金額は 49.90 です。

データベースのスナップショットを作成します。

aws rds \
  create-db-snapshot \
  --db-instance-identifier orders-db \
  --db-snapshot-identifier orders-before-delete \
  --query 'DBSnapshot.{Snapshot:DBSnapshotIdentifier,Source:DBInstanceIdentifier,Status:Status}'
aws rds \
  wait db-snapshot-available \
  --db-snapshot-identifier orders-before-delete
aws rds \
  describe-db-snapshots \
  --db-snapshot-identifier orders-before-delete \
  --query 'DBSnapshots[].{Snapshot:DBSnapshotIdentifier,Type:SnapshotType,Source:DBInstanceIdentifier,Status:Status}'

orders-db の手動スナップショットが available になります。AWS View にプライマリと新しいスナップショットが表示されます。次の変更を行う前に完了を待ってください。

意図的なデータ損失を観察する

このステップでは、サンプル注文を 1 件だけ削除し、アプリケーションのデータを観察します。

以下の削除はこの練習のために意図的に行います。WHERE が対象を注文 101 に限定します。

psql \
  "service=orders-db" \
  --set=ON_ERROR_STOP=1 \
  --command 'DELETE FROM orders WHERE order_id = 101;'

残った行を読み取ります。

psql \
  "service=orders-db" \
  --command 'SELECT order_id, customer, total FROM orders ORDER BY order_id;'

102 と 103 だけが表示されます。アプリケーションの一覧を取得します。

curl \
  --silent \
  --show-error \
  --fail \
  http://127.0.0.1:8080/application/orders | jq

アプリケーションは接続して応答しますが、Maya の注文がありません。接続が正常でも業務データが完全とは限りません。削除前のスナップショットには必要な回復用コピーがあります。

新しいインスタンスを復元してアプリを切り替える

このステップでは、新しいインスタンスにスナップショットを復元し、アプリが復元データを読むことを確認します。

スナップショットの復元は新しい RDS インスタンスを作成します。既存のインスタンスをその場で巻き戻す操作ではありません。異なる識別子を使い、用意されたサブネットグループとセキュリティグループを明示的に選びます。

復元で新しいエンドポイントが作られ、破線でロールバックされない元の DB と比較

概念図:復元で新しいエンドポイントが作られ、破線でロールバックされない元の DB と比較。

aws rds \
  restore-db-instance-from-db-snapshot \
  --db-instance-identifier orders-restored \
  --db-snapshot-identifier orders-before-delete \
  --db-instance-class db.t3.micro \
  --db-subnet-group-name orders-subnets \
  --vpc-security-group-ids "$DB_SECURITY_GROUP_ID" \
  --no-publicly-accessible \
  --query 'DBInstance.{Identifier:DBInstanceIdentifier,Status:DBInstanceStatus,Endpoint:Endpoint}'
aws rds \
  wait db-instance-available \
  --db-instance-identifier orders-restored

用意された接続設定で新しいエンジンをクエリします。

psql \
  "service=orders-restored" \
  --command 'SELECT order_id, customer, total FROM orders ORDER BY order_id;'

元の 3 件すべてが表示されます。元のデータベースを別途確認します。

psql \
  "service=orders-db" \
  --command 'SELECT order_id, customer, total FROM orders ORDER BY order_id;'

元のデータベースには引き続き 102 と 103 だけがあります。変更済みの元のインスタンスと回復したデータベースという、独立した 2 つのインスタンスができました。

復元したエンドポイントを取得し、アプリケーションの両方のホストフィールドを更新します。

RESTORED_ENDPOINT=$(aws rds \
  describe-db-instances \
  --db-instance-identifier orders-restored \
  --query 'DBInstances[0].Endpoint.Address' \
  --output text)
jq \
  --arg host "$RESTORED_ENDPOINT" \
  '.read_host = $host | .write_host = $host' \
  app-config.json > app-config.new
mv app-config.new app-config.json

アプリケーションをテストします。

curl \
  --silent \
  --show-error \
  --fail \
  http://127.0.0.1:8080/application/orders | jq

再び 101、102、103 が表示されます。AWS View に両方のインスタンスと回復した注文が表示されます。インスタンスを作成しただけでなく、アプリが復元先に接続して期待するレコードを利用できることが回復の完了条件です。

スナップショットには削除前に取得したデータが含まれます。バックアップ後の変更は、復元したインスタンスに自動では反映されません。回復計画には、バックアップ時刻とアプリの切り替え判断が重要です。 アプリケーションが独立して復元された PostgreSQL インスタンスから回復した注文を読み取っています。

両方のインスタンスと手動スナップショットを削除する

このステップでは、使用した各回復リソースを削除します。

復元インスタンスと元の練習用インスタンスを削除します。

aws rds \
  delete-db-instance \
  --db-instance-identifier orders-restored \
  --skip-final-snapshot \
  --query 'DBInstance.DBInstanceIdentifier'
aws rds \
  delete-db-instance \
  --db-instance-identifier orders-db \
  --skip-final-snapshot \
  --query 'DBInstance.DBInstanceIdentifier'
aws rds \
  wait db-instance-deleted \
  --db-instance-identifier orders-restored
aws rds \
  wait db-instance-deleted \
  --db-instance-identifier orders-db

手動スナップショットはインスタンスとは独立しているため、別途削除します。

aws rds \
  delete-db-snapshot \
  --db-snapshot-identifier orders-before-delete \
  --query 'DBSnapshot.DBSnapshotIdentifier'

両方のリソース一覧を確認します。

aws rds \
  describe-db-instances \
  --query 'DBInstances[].DBInstanceIdentifier'
aws rds \
  describe-db-snapshots \
  --snapshot-type manual \
  --query 'DBSnapshots[].DBSnapshotIdentifier'

両方とも [] になります。AWS View にデータベースや手動スナップショットが残っていないことを確認し、用意されたアプリとネットワークは保持してください。

まとめ

手動スナップショットを作成し、意図的な削除を観察して、保存データを新しいインスタンスに復元しました。アプリのエンドポイントを切り替えることで、元のデータベースを変更せずに注文を回復しました。その後、両インスタンスと独立したスナップショットを削除しました。

次の実習では、PostgreSQL リードレプリカを使ってアプリの読み取りと書き込みを分離します。