RDS のスナップショットから復元したクローンで general_log を採取してみた

RDS のスナップショットから復元したクローンで general_log を採取してみた

2026.05.19

はじめに

かつまたです。

RDS の利用状況を把握するため mysql.general_log を採取したい場面はよくあります。
ただし本番 DB に対しては、なるべく作業用接続を増やしたくないという運用方針を取っているケースも多いはずです。

そこで今回は、本番 RDS のスナップショットから復元したクローン DB に対して mysql.general_log を採取できるかを試してみました。

結論から言うと、スナップショット取得時点までに蓄積されたログはクローン側にそのまま引き継がれており、クローン経由で問題なく採取できることが確認できました。

やりたいこと

  • 本番 RDS(MySQL)に 直接接続せず に、過去のクエリログと接続元 IP を採取する
  • 採取の流れ
    1. 本番 RDS のスナップショット取得
    2. スナップショットからクローン DB を復元
    3. クローン DB の master password を作業用に再設定
    4. CloudShell からクローン DB に接続して mysql.general_log を採取

前提条件

  • 本番 RDS のカスタムパラメータグループ側で general_log = 1 / log_output = TABLE は既に有効化済み
    • これにより本番 RDS の mysql.general_log テーブルにクエリが蓄積された状態であること
  • 採取作業は AWS CloudShell(東京リージョン)から実施
  • 本番 RDS は private subnet 配置、--no-publicly-accessible の前提
  • クローン DB は採取が終わったら削除する短期利用前提

やってみた

1. 本番 RDS のスナップショットを取得

CloudShell で日付を変数にして取得します。

DATE=$(date +%Y%m%d)

aws rds create-db-snapshot \
  --region ap-northeast-1 \
  --db-instance-identifier mydb \
  --db-snapshot-identifier mydb-restore-snap-${DATE}

完了を待機し、ステータス確認。

aws rds describe-db-snapshots \
  --region ap-northeast-1 \
  --db-snapshot-identifier mydb-restore-snap-${DATE} \
  --query 'DBSnapshots[0].[DBSnapshotIdentifier,Status,SnapshotCreateTime]' \
  --output table

Status=available になっていれば OK です。

2. スナップショットからクローン DB を復元

クローン DB は後ほど CloudShell からインターネット経由で接続するため、Public Subnet(IGW ルートあり)を含む DB サブネットグループ に配置します。
該当する DB サブネットグループがなければ、事前に作成しておきます。

aws rds create-db-subnet-group \
  --region ap-northeast-1 \
  --db-subnet-group-name mydb-clone-public-sng \
  --db-subnet-group-description "for clone DB to capture general_log" \
  --subnet-ids <PublicSubnetId-1> <PublicSubnetId-2>

SG は本記事では本番のものを流用するため、まず取得します。

本記事では検証のため本番 RDS の SG をそのまま流用していますが、本番運用環境では、後述の 4 で SG にルール追加する関係上、クローン専用 SG を新規作成して割り当てる構成が望ましいです。本番 SG を直接編集すると、タイポやルール撤去漏れが本番 RDS にも波及するリスクがあります。

aws rds describe-db-instances \
  --region ap-northeast-1 \
  --db-instance-identifier mydb \
  --query 'DBInstances[0].VpcSecurityGroups[*].VpcSecurityGroupId' \
  --output text

得られた SG とクローン用サブネットグループを指定して復元します。インスタンスクラスは本番より小さく db.t3.micro にしてコストを抑え、--publicly-accessible も合わせて指定します。

SG=<取得値>

aws rds restore-db-instance-from-db-snapshot \
  --region ap-northeast-1 \
  --db-instance-identifier mydb-restore-${DATE} \
  --db-snapshot-identifier mydb-restore-snap-${DATE} \
  --db-instance-class db.t3.micro \
  --no-multi-az \
  --publicly-accessible \
  --db-subnet-group-name mydb-clone-public-sng \
  --vpc-security-group-ids ${SG}

復元完了待機し、エンドポイントと MasterUsername を確認。

aws rds describe-db-instances \
  --region ap-northeast-1 \
  --db-instance-identifier mydb-restore-${DATE} \
  --query 'DBInstances[0].[DBInstanceStatus,Endpoint.Address,Endpoint.Port,MasterUsername]' \
  --output table

MasterUsername は本番から引き継がれます(本記事では admin)。

3. クローン DB の master password を作業用に再設定

クローン DB は復元直後に modify-db-instance --master-user-passwordmaster password を新しく上書き設定できます
本番 DB とは独立した作業用パスワードをクローン側に付けて、そのパスワードで mysql クライアントから接続します。

CLONE_PASSWORD=$(openssl rand -base64 32 | tr -d '/+=@"' | head -c 24)
echo "clone password: ${CLONE_PASSWORD}"

aws rds modify-db-instance \
  --region ap-northeast-1 \
  --db-instance-identifier mydb-restore-${DATE} \
  --master-user-password "${CLONE_PASSWORD}" \
  --apply-immediately

master-user-password は dynamic のため、再起動なしで 1〜2 分以内に反映されます。

反映確認。

aws rds describe-db-instances \
  --region ap-northeast-1 \
  --db-instance-identifier mydb-restore-${DATE} \
  --query 'DBInstances[0].PendingModifiedValues'

戻り値が {} であれば、保留中の変更なし=反映完了です。

4. CloudShell からクローン DB に接続するための SG 設定

クローン DB はステップ 2 で --publicly-accessible 指定済み・Public Subnet 配置済みなので、ネットワーク層では既にインターネットから到達可能な状態です。あとは SG で CloudShell の egress IP に対してだけ 3306 を許可します。

https://docs.aws.amazon.com/ja_jp/cloudshell/latest/userguide/using-cshell-in-vpc.html

4-1. クローン DB のエンドポイントを取得

ENDPOINT=$(aws rds describe-db-instances \
  --region ap-northeast-1 \
  --db-instance-identifier mydb-restore-${DATE} \
  --query 'DBInstances[0].Endpoint.Address' --output text)

getent hosts ${ENDPOINT}

返ってきた IP が 13.x / 18.x / 35.x などのグローバル IP であることを確認します。
10.x / 172.x が返る場合は Public IP 付与の DNS 伝播待ち。

4-2. SG に CloudShell の IP を一時許可

CloudShell の egress IP を取得します。

CLOUDSHELL_IP=$(curl -s https://checkip.amazonaws.com)
echo ${CLOUDSHELL_IP}

クローン DB の SG に対して 3306 を一時許可します。作業完了後の撤去用に Description を付けておく のがおすすめです。

aws ec2 authorize-security-group-ingress \
  --region ap-northeast-1 \
  --group-id ${SG} \
  --ip-permissions "IpProtocol=tcp,FromPort=3306,ToPort=3306,IpRanges=[{CidrIp=${CLOUDSHELL_IP}/32,Description=\"TEMP CloudShell clone access - REMOVE AFTER\"}]"

返ってきた SecurityGroupRuleIdsgr-xxxx)を控えます。撤去時に使います。

5. mysql クライアントから接続して general_log を採取

CloudShell に mysql クライアントを入れます。Amazon Linux 2023 ベースの CloudShell では mysql パッケージは廃止されているため、mariadb105 を入れて mysql コマンドを使います。

sudo dnf install -y mariadb105

接続して、まずスナップショット取得時点までのログ件数を確認します。

mysql -h ${ENDPOINT} -P 3306 -u admin -p"${CLONE_PASSWORD}" -e "
SELECT COUNT(*) AS total_rows,
       MIN(event_time) AS first_event,
       MAX(event_time) AS last_event
FROM mysql.general_log;
"

出力例(本番側で general_log を有効化した時点〜スナップショット取得時点までの範囲)

+------------+----------------------------+----------------------------+
| total_rows | first_event                | last_event                 |
+------------+----------------------------+----------------------------+
|     142385 | 2026-05-07 10:00:12.118203 | 2026-05-15 09:58:33.624117 |
+------------+----------------------------+----------------------------+

スナップショット取得時点までの event_time 範囲でログが取得できれば、クローンに general_log が引き継がれている ことの確認になります。

実クエリログを CSV に出力します。

mysql -h ${ENDPOINT} -P 3306 -u admin -p"${CLONE_PASSWORD}" -e "
SELECT event_time, user_host, command_type, LEFT(argument, 500) AS query
FROM mysql.general_log
WHERE user_host NOT LIKE '%rdsadmin%'
ORDER BY event_time;
" > general_log_${DATE}.csv

出力された CSV の中身は以下のようなイメージです(抜粋)

event_time	user_host	command_type	query
2026-05-07 10:00:13.452881	appuser[appuser] @  [10.0.12.34]	Connect	appuser@10.0.12.34 on appdb using TCP/IP
2026-05-07 10:00:13.453902	appuser[appuser] @  [10.0.12.34]	Query	SELECT id, name, status FROM users WHERE id = 1024
2026-05-07 10:00:13.461230	appuser[appuser] @  [10.0.12.34]	Query	UPDATE sessions SET last_access = NOW() WHERE token = '...'
2026-05-09 14:23:10.882104	dbtool[dbtool] @  [192.168.10.20]	Query	SHOW TABLES

接続元 IP の集計も合わせて取得しておくと、削除可否判断の材料として便利です。

mysql -h ${ENDPOINT} -P 3306 -u admin -p"${CLONE_PASSWORD}" -e "
SELECT
  SUBSTRING_INDEX(SUBSTRING_INDEX(user_host, '[', -1), ']', 1) AS source_ip,
  COUNT(*) AS query_count,
  MIN(event_time) AS first_seen,
  MAX(event_time) AS last_seen
FROM mysql.general_log
WHERE user_host NOT LIKE '%rdsadmin%'
GROUP BY source_ip
ORDER BY query_count DESC;
" > source_ip_${DATE}.csv

出力された CSV (例)

source_ip	query_count	first_seen	last_seen
10.0.12.34	78214	2026-05-07 10:00:13	2026-05-15 09:58:33
10.0.12.35	63892	2026-05-07 10:00:15	2026-05-15 09:58:32
192.168.10.20	18	2026-05-09 14:23:10	2026-05-09 14:25:42

CloudShell の「アクション」→「ファイルのダウンロード」で手元に取得します。

結果

項目 結果
クローン DB の mysql.general_log 件数 スナップショット取得時点までのログを保持
採取したクエリの event_time 範囲 本番側で有効化した時刻〜スナップショット取得時刻
本番 RDS への接続実績 0 件(一切接続せず採取完了)
本番 RDS の master password 触れていない(クローン側に作業用パスワードを設定)
本番 RDS の再起動 発生なし

スナップショットには mysql スキーマも含まれるため、mysql.general_log テーブルの内容も復元されることを確認できました。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_RestoreFromSnapshot.html

本番 RDS に対して mysql クライアントから接続することなく、過去のクエリログと接続元 IP の採取が完結できました。

おわりに

スナップショット → クローン復元という流れだけで、本番 RDS に一切接続することなく mysql.general_log の中身を採取できることを確認できました。
本番への影響を避けたい運用調査の選択肢として、覚えておくと便利な手段だと感じました。

ご覧いただきありがとうございました。

クラスメソッドオペレーションズ株式会社について

クラスメソッドグループのオペレーション企業です。
運用・保守開発・サポート・情シス・バックオフィスの専門チームが、IT・AIをフル活用した「しくみ」を通じて、お客様の業務代行から課題解決や高付加価値サービスまでを提供するエキスパート集団です。
当社は様々な職種でメンバーを募集しています。
「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、クラスメソッドオペレーションズ株式会社 コーポレートサイト をぜひご覧ください。
※2026年1月 アノテーション㈱から社名変更しました

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事