1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】RDS Proxy環境でAurora MySQL 5.7から8.0へCloudFormationで安全に移行した話(ハマりポイント集)

1
Last updated at Posted at 2025-12-24

はじめに

Aurora MySQL 5.7 のEOL に伴い、MySQL 8.0 へのバージョンアップする業務を担当した。
対象のシステムは CloudFormation (IaC) で管理されており、かつ RDS Proxy を利用している構成である。
この環境下でのアップグレードで、IaCの制約、MySQL 8.0の仕様変更、インフラの罠に次々と遭遇した。
本記事では、「DBの深淵とAWSの仕様に立ち向かった記録」 として、採用した移行戦略とハマりポイントをまとめた。

システム構成と要件

  • 現: Aurora MySQL 5.7 (db.t2.medium)
  • 新: Aurora MySQL 8.0 (db.t3.medium)
  • 構成: CloudFormation (IaC) 管理
  • 接続: Lambda -> RDS Proxy -> Aurora Cluster

比較:MySQL 5.7 vs 8.0(移行時の主要変更点)

比較項目 MySQL 5.7 (Aurora v2) MySQL 8.0 (Aurora v3) 影響と対策
インスタンス型式 T2, T3, R5など幅広く対応 T2系は非対応 (T3以降) インスタンスクラスの変更が必須
GROUP BY句 曖昧なカラム指定も許容 厳格化 (ONLY_FULL_GROUP_BY) クエリの修正が必要になる可能性大
ソート順 GROUP BYで自動ソート 自動ソート廃止 順序が重要な場合はORDER BYを追記
バイナリ型 Buffer(Node.js特有) Uint8Array(標準) Base64変換等のコード修正が必要

【移行の要件】

  1. ダウンタイムを最小限にする
  2. 問題発生時に容易にロールバックができること
  3. アプリケーション側の接続先変更(エンドポイント書き換え)を発生させないこと

移行戦略:「並行稼働」

今回の移行では、「旧DB(v5.7)新DB(v8.0) を並行して稼働させ、RDS Proxyの向き先を変える」 という戦略を採用した。

なぜ「スナップショット」(データのコピー)

公式の「Blue/Greenデプロイ機能」は、RDS ProxyやCloudFormation管理下では制約が多く使えなかった。
そこで、「メンテナンス開始直後の旧DBのスナップショット(データのコピー)を取得し、そこから新DBで復元する」 手順を取った。
また、旧DBには一切手を加えないため、データが壊れず、ロールバックがしやすいメリットもある。

実際のデプロイフロー

CloudFormationテンプレート上で、以下のようにリソースを定義した

  1. 準備: 旧DB (DBCluster) はそのまま定義を残す

  2. 構築: 新DB (DBClusterV8) を定義し、プロパティ SnapshotIdentifier に取得したスナップショットARNを指定する

  3. 切替: RDS Proxy のターゲットグループ定義 (RdsProxyTargetGroup) を、旧DB (DBCluster) から 新DB (DBClusterV8) に書き換えてデプロイ

  4. 切り戻し: 切り戻しが必要になった際のロールバックは、RDS Proxyのターゲットを DBCluster (旧) に戻してデプロイし直すだけで元の状態に戻せる

インフラ(CloudFormation)の競合回避

ここからは、実際に遭遇したエラーと解決策

1. SecretAttachmentの競合エラー

新DBを作成する際、既存の AuroraSecret (Secrets Manager) を紐付けようとして、AWS::SecretsManager::SecretTargetAttachment を定義したところ以下の様なエラーが発生した。

  • エラー文: Resource handler returned message: "... already exists in stack ..."
  • 原因: CloudFormationの仕様上、1つのシークレットに対して定義できるSecretTargetAttachmentは1つだけで、既に旧DBに紐付いているため新DBにも同時に紐付けようとして競合した
  • 解決策: 新DB用のSecretTargetAttachment定義を削除し、DBクラスター定義側で動的参照を使用することで解決した
  DBClusterV8:
    Type: AWS::RDS::DBCluster
    Properties:
      # SecretTargetAttachmentを使わず、ここで直接参照する
      MasterUserPassword: '{{resolve:secretsmanager:AuroraSecret:SecretString:password}}'

2. インスタンスタイプ (T2 vs T3)

新DBのインスタンスクラスを、旧DBと同じ db.t2.medium に設定してデプロイしたところエラーになった

  • エラー:RDS does not support creating a DB instance with the following combination.
  • 原因: Aurora MySQL v3 (8.0) は、T2系インスタンスをサポートしていなかった
  • 解決策: 新DBの定義のみdb.t3.mediumに変更した

3. RDS Proxyエンドポイント名の重複

RDS Proxyのエンドポイント定義 (AWS::RDS::DBProxyEndpoint) において、論理IDを変更してデプロイしようとしたところエラーになった

  • エラー:The DBProxyEndpoint 'olc-proxyendPoint' already exists
  • 原因: AWS上の実体は ...-proxyEndPoint (Eが大文字) だったが、テンプレートで ...-proxyendPoint(eが小文字) と書いてあった。 CFnは「名前変更=リソース置換(作り直し)」と判断したが、MySQL/AWSの仕様上、大文字小文字の違いだけでは「同名」とみなされ、「すでに存在する」と怒られた
  • 解決策: 既存のエンドポイント名と一字一句合わせるか、新定義の末尾に -v8 を付けるなどして完全に別名にした

アプリ・DB内部 (MySQL 8.0)

4. MySQL 8.0 の「GROUP BY」厳格化

移行において最も警戒されていたのが、SQL構文ルールの厳格化、特に GROUP BY の挙動変更

リスク1:「曖昧な GROUP BY」がエラーになる

MySQL 5.7(のデフォルト設定)では、以下のようなクエリが許容されていた

-- 5.7では動くが、8.0ではエラーになる可能性がある
SELECT class, MAX(score), student_name 
FROM test_results 
GROUP BY class;

GROUP BY class しているのに、集計関数を通していない student_nameSELECTしてる。
5.7では「適当な誰かの名前」を返してくれたが、8.0では 「どの生徒の名前を出せばいいか曖昧だ」 としてエラーになる

リスク2:暗黙のソート廃止

MySQL 5.7では GROUP BY を書くと、結果が自動的にソート(昇順)されていた。
しかし、8.0ではこの仕様が廃止されたので、ORDER BY を明示していない画面では、バージョンアップ後に表示順序がバラバラになるリスクがある。

5. 実行計画 (EXPLAIN) の罠:「データ量」

「バージョンアップに伴いDBへの読み込み速度」を確認するため、EXPLAIN コマンドで実行計画を確認した。
しかし、開発環境で検証中に type: ALL(全件スキャン)が出るケースがあったので、パフォーマンスの劣化を疑った。

  • 原因: 開発環境のデータ量が少なすぎたため、オプティマイザが「インデックスを使うより全件読んだ方が速い」と判断していただけだった

  • 対応策: 本番想定のデータ量(数万件)を投入して再検証したら、 type: ref に切り替わることを確認した

「今の実行計画」だけでなく、「本番規模のデータ量でどう動くか」を検証する重要性 を学んだ

6.データの同一性証明 (CHECKSUM TABLE)

移行前後でデータが破損していないか証明するため、これまで COUNT(件数)しか見ていなかったが、CHECKSUM TABLEコマンドを使用して、データの中身も保証されていることを確認した。
そこで、レコード数や最終更新日時も変わっていないのに、チェックサムの値だけが変わる テーブルがあった。

  • CHECKSUM TABLEコマンド
    テーブルの中身(全データのバイト列)を計算してハッシュ値を出すコマンドである。
    移行前後で「件数は合っているが、文字化けしてない?データ壊れてない?」を証明するために用いた

  • 原因: JSON型や長大なVARCHAR型を持つテーブルにおいて、ORMが全カラム更新(値は同じ)をかけた際、論理的な値は同じでもMySQL内部(InnoDB)での物理的なバイナリ配置が整理され、チェックサムが変わると判明

  • 解決策: 「チェックサムの値が違う=NG」と即断せず、最終更新日時や SHOW PROCESSLIST(接続状況)を併用して、「業務データに変更がないこと」を多角的に証明した

まとめ

今回の移行プロジェクトを通じて、以下の知見が得られた

  1. インフラの競合回避: CloudFormationでは、新旧の環境で名前や設定(パスワード管理等)がぶつからないよう設計を工夫する
  2. SQLルールの厳格化: MySQL 8.0では、5.7で許容されていた「曖昧な書き方(GROUP BY等)」がエラーになるため、事前修正が必須
  3. データ検証の注意点: データの指紋(チェックサム)を確認する際、中身が同じでも「保存形式の変化」で値が変わる場合もある
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?