0
0

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 Blue/Green デプロイメントでMySQLをメジャーアップグレードしてみた

0
Posted at

はじめに

本番で動いている RDS MySQL を、Blue/Green Deployments を使って 8.0 から 8.4(LTS)へメジャーアップグレードしてみました。

本データベースはリードオンリー中心ですが、24/365 で断続的にアクセスが発生しています。ただ、Single-AZ 構成でずっと運用していたため、その構成のままでも極力停止時間が短くなるようにしたいということで、今回の方式を採用しました。

まずは結論から

  • Blue/Green なら切り替え前に新バージョンの接続確認できる
  • 切り替えする際もアプリの接続先は変えなくていい
  • 切り替えの瞬間は完全な無停止ではない
  • 自動ロールバックは無い

想定される読者

  • RDS のメジャーアップグレードで、ダウンタイムを抑えたい方
  • Blue/Green Deployments を実際に使うとどうなるか知りたい方
  • 冗長化していないRDSを運用していて、アップグレードを控えている方

アップグレードに至った経緯

きっかけは Extended Support(標準サポート終了後の有償サポート)の課金でした。MySQL 8.0 の標準サポートは 2026年7月31日で終了し、それ以降は Extended Support が有効でないDBは定期メンテナンスウィンドウで自動的に 8.4 へアップグレードされます。RDS のコンソールにも、以下のようなレコメンデーションが届いていました。

RDSBlueGreenRecommendation.png

自動アップグレードをそのまま迎えるわけにはいきませんし、Extended Support の課金もそこそこ負担になりますので、早めにアップグレードしてみることにしました。

現状確認

対象のDBはこういう構成でした。

項目 値
エンジン MySQL 8.0.45
インスタンスクラス db.t3.micro
配置 Single-AZ(冗長化なし)
ストレージ 200GB
接続経路 RDS Proxy 経由 + 一部アプリは直結
接続数 平均 0.5〜5
稼働 24時間365日

接続数はそこまで多くないものの、止められそうな時間帯もなかったので、アップグレードする際も出来るだけダウンタイムを短くする必要がありました。

アップグレード方式の選定

ダウンタイムを短くする観点で、選択肢を整理しました。

手段 ダウンタイム 今回の可否
インプレースアップグレード 10〜30分 止まるので不可
Multi-AZ DB クラスターで実施 約35秒 今回のインスタンスクラスは対象外
リードレプリカを作って昇格 短くできる 手作業が多い
Blue/Green Deployments 十数秒〜 採用

今回は Blue/Green Deployments を選びました。現行環境(blue)のレプリカとして新バージョンの環境(green)を自動で作り、レプリケーションで同期させながら好きなタイミングで切り替えられる仕組みです。

今回 Single-AZ 構成だからダウンタイムのことを気にしないといけないと思いましたが、単純な Multi-AZ 構成でも同じみたいです。メジャーアップグレード時にプライマリとスタンバイを同時に上げるため、完了までDBは使えなくなるそうです(公式ドキュメント)。

事前チェック

アップグレード先の選択

現行 8.0.45 からの移行先を確認します。

aws rds describe-db-engine-versions \
  --engine mysql \
  --engine-version 8.0.45 \
  --query 'DBEngineVersions[0].ValidUpgradeTarget[?IsMajorVersionUpgrade==`true`].EngineVersion' \
  --region ap-northeast-1

8.4.3 から 8.4.11 までが選択できました。今回は現時点の最新である 8.4.11 にします。

8.0から8.4への非互換

8.0 から 8.4 へのアップグレードには専用のプリチェック項目があり、アップグレード実行時に RDS が自動で検査します。互換性の問題が見つかった場合はアップグレードが中断され、DBは元の状態のまま残ります。

中でも影響が出やすいのが認証プラグインです。

バージョン デフォルト認証プラグイン
RDS MySQL 8.0.34以降 mysql_native_password(変更不可)
RDS MySQL 8.4以降 caching_sha2_password

MySQL にアクセスする際の認証プラグインが新しい方式(caching_sha2_password)に変更になっています。ただ、既に旧方式(mysql_native_password)で作られているユーザーはアップグレード後もそのまま接続できるので、今回は対応不要です。アプリ側への影響もありません。

ただし mysql_native_password は将来のバージョンで削除される予定です。そのときは認証方式の移行が必要になりますが、ユーザーを作り直す必要はなく、ALTER USER ... IDENTIFIED WITH caching_sha2_password で切り替えるだけです。

また、今回接続しているアプリ(Lambda)を確認したところ、MySQL クライアントは新方式にも対応している mysql2(3.6系)を使っていました。将来 MySQL ユーザーを作ったり既存ユーザーの認証方式を移行したりしても、認証で詰まる心配はなさそうです。

Blue/Green の前提条件

確認した結果、今回は追加作業なしで使えました。

条件 状態
binlog が有効 OK(自動バックアップ保持7日 = binlog有効)
カスタムオプショングループ未使用 OK(default:mysql-8-0)
パラメータグループ default.mysql8.0 → 8.4化で default.mysql8.4 が自動適用

binlog は自動バックアップの保持期間が1日以上あれば有効になっています。ここが0だと Blue/Green は使えません。

カスタムオプショングループを使っている場合は、Blue/Green 作成時にメジャーアップグレードを同時指定できません。その場合は Blue/Green を作ってから green 側をアップグレードする、という2段構えになります。

アップグレードの実践

では、実際に Blue/Green Deployments にてアップグレードを実施していきます。
RDS の機能として準備されていますので、基本的にはコンソール上でポチポチ選択していくことで進められます。

スナップショットの取得

対象のDBを選択して、「アクション」→「スナップショットの取得」。

RDSBlueGreenSnapShot.png

自動スナップショットは毎日取られていますが、アップグレード直前の状態を残しておきます。

もちろん CLI でも進められます。

aws rds create-db-snapshot \
  --db-instance-identifier <DB_IDENTIFIER> \
  --db-snapshot-identifier pre-84-upgrade \
  --region ap-northeast-1

Blue/Green Deployment の作成

対象のDBを選択して、「アクション」→「ブルー/グリーンデプロイの作成」。

green 環境を 8.4.11 で作ります。

RDSBlueGreenBlueGreen.png

aws rds create-blue-green-deployment \
  --blue-green-deployment-name mysql-84-upgrade \
  --source arn:aws:rds:ap-northeast-1:<ACCOUNT_ID>:db:<DB_IDENTIFIER> \
  --target-engine-version 8.4.11 \
  --region ap-northeast-1

進捗は以下のように確認できます。

RDSBlueGreenBlueGreenCreating.png

green 環境の作成には、体感で15〜20分ほどかかりました。裏では新しいDBインスタンスを立ち上げ、blue のレプリカとしてレプリケーションを張るところまでを自動でやってくれます。この間、blue(本番)は通常どおり動き続けます。

プリチェックでのエラー発生

ここで一度つまずきました。green 環境は出来ましたが、その後の手順がなかなか進みません。
コンソールを確認したところ、エラーになってました。
RDSBlueGreenBlueGreenError.png

コンソールにはこう表示されていました。

Failed to provision due to upgrade incompatibilities. Resolve the issues and manually upgrade the green environment to version 8.4.11 by September 18. The blue/green deployment will resume automatically after the upgrade is complete.

green 環境を作る際、8.0 → 8.4 のプリチェックで非互換が見つかり、プロビジョニングが止まった状態です。green はまだ 8.0.45 のまま生きていて、非互換を解消して green を手動で 8.4 に上げれば、Blue/Green が自動で再開するという内容です。

非互換の内容

原因は green のログ PrePatchCompatibility.log に出ていました。

2) Issues reported by 'check table x for upgrade' command
    STORE_SETTINGS_VIEW    - references invalid table(s) or column(s)... / Corrupt
    STORE_INTEGRATION_VIEW - references invalid table(s) or column(s)... / Corrupt

参照先のテーブルやカラムが存在しなくなった、壊れたビューが2つあり、CHECK TABLE ... FOR UPGRADE が Corrupt と判定していました。この破損ビューが原因で、Blue/Green 環境の生成が止まっていました。

壊れたビューの削除

blue(本番)に接続して、問題のビューを確認しました。定義自体は取得できますが、SELECT するとエラーになります。

-- 定義は見られる
SHOW CREATE VIEW STORE_SETTINGS_VIEW\G

-- SELECT するとエラー(=すでに機能していない)
SELECT * FROM STORE_SETTINGS_VIEW;
-- ERROR 1356 (HY000): View '...' references invalid table(s) or column(s)...

このビューはアプリのコードからも他のビューからも参照されてなかったので、削除しました。

-- 消す前に、他のビューから参照されていないことを確認
SELECT TABLE_SCHEMA, TABLE_NAME
FROM information_schema.VIEWS
WHERE VIEW_DEFINITION LIKE '%STORE_SETTINGS_VIEW%'
   OR VIEW_DEFINITION LIKE '%STORE_INTEGRATION_VIEW%';
-- Empty set = 依存なし

-- 削除
DROP VIEW STORE_SETTINGS_VIEW;
DROP VIEW STORE_INTEGRATION_VIEW;

green の手動アップグレード

破損ビューを消したら、案内どおり green を手動で 8.4.11 にアップグレードします。プリチェックのブロッカーが消えているので、今度は通ります。green のアップグレードが完了すると、Blue/Green は自動的に AVAILABLE(利用可能) に復帰します。

RDSBlueGreenBlueGreenReStart.png

aws rds modify-db-instance \
  --db-instance-identifier <GREEN_DB_IDENTIFIER> \
  --engine-version 8.4.11 \
  --allow-major-version-upgrade \
  --apply-immediately \
  --region ap-northeast-1

今回は、破損ビューを消したあとのプリチェックは約20秒で通過し、エンジンの更新自体は約2分で完了しました。その後 green は自動バックアップの再設定などの後処理に入り、数分後に Blue/Green のステータスが AVAILABLE に戻りました。

RDSBlueGreenBlueGreenAvailable.png

green環境の確認

green ができたら状態を確認します。レプリケーション遅延がゼロになっているかを見ます。

RDSBlueGreenBlueGreenPrepare.png

aws rds describe-blue-green-deployments \
  --blue-green-deployment-identifier <BG_ID> \
  --region ap-northeast-1

スイッチオーバーマッピングのステータスが AVAILABLE(利用可能)になっていれば、切り替え可能な状態です。

今回は念のため、切り替え前に green のエンドポイントに接続して、バージョンを確認しました。

$ mysql -h <GREEN_ENDPOINT> -u admin -p -e "SELECT VERSION();"

RDSBlueGreenBlueGreenVersionCheck.png

caching_sha2_password 絡みの認証エラーも出ず、問題なく 8.4.11 に接続できました。このように切り替え前に具体的な確認ができるのが、Blue/Green の安心材料です。必要に応じてアプリから接続しての動作確認も可能です。

切り替え

問題なければ切り替えます。
作成したブルー/グリーンデプロイの「アクション」→「切り替え」を選択。

切り替え前後の状態を確認して、問題なければ実行します。
RDSBlueGreenBlueGreenCompare.png

aws rds switchover-blue-green-deployment \
  --blue-green-deployment-identifier <BG_ID> \
  --switchover-timeout 300 \
  --region ap-northeast-1

切り替え時、RDS は内部でこういう順序で動いています。

  1. ガードレールチェック(両環境が切り替え可能な状態か検証)
  2. 両環境で新規の書き込みを停止
  3. 両環境のコネクションを切断し、新規接続を止める
  4. green のレプリケーションが追いつくのを待つ
  5. 識別子とエンドポイントを入れ替える(旧 blue には -old1 が付く)
  6. 接続を再開し、新環境で書き込みを許可

5番が実行されることで、アプリの接続先エンドポイントが変わることなくデータベースの置き換えが可能となっています。

コンソール上では、次のように RDS が自動で切り替えを進めていきます。
RDSBlueGreenBlueGreenSwitchOver.png

実際に切り替えてみた結果、RDS のイベントにはこう記録されました。

The primary azsystems-db-green environment is now accepting read and write operations at the database level. The write downtime during the switchover lasted approximately 1 seconds.

書き込みのダウンタイムは約1秒でした。事前に「十数秒程度の書き込みエラーと再接続が起きる前提」で臨んでいましたが、実測はそれよりずっと短く収まりました。

RDSBlueGreenBlueGreenResult.png

切り替え後の確認

切り替わったら、旧環境を消す前に確認します。まずインスタンスの状態です。
RDSBlueGreenBlueGreenConfirm.png

見るべきポイントは次のとおりです。

確認項目 期待値
新環境のエンジンバージョン 8.4.11
新環境の識別子 元の識別子のまま
パラメータグループ default.mysql8.4 に切り替わっている
ストレージタイプ 元の設定が維持されている
旧環境の識別子 -old1 が付いた状態で存在

新環境が元の識別子を引き継いで 8.4.11 になり、パラメータグループも default.mysql8.4 に切り替わっています。ストレージタイプは維持。旧環境は xxx-old1 として 8.0.45 のまま残っています。

aws rds describe-db-instances \
  --region ap-northeast-1 \
  --query 'DBInstances[].{id:DBInstanceIdentifier,version:EngineVersion,storage:StorageType,pg:DBParameterGroups[0].DBParameterGroupName,status:DBInstanceStatus}'

アプリからの接続

最後にアプリからの接続状況を確認します。ポイントは以下。

  • アプリからの読み取り・書き込みが通るか
  • 接続エラーやタイムアウトがログに出ていないか
  • 認証エラー(caching_sha2_password 絡み)が出ていないか

今回は RDS Proxy 経由の接続と、直結の接続が混在していました。
切り替え前後のログを CloudWatch で確認したところ、いずれの処理も START → END と正常終了しており、エラーはゼロ。接続エラーや pymysql 絡みの例外も出ていませんでした。問題なし。

旧環境の削除

切り替え後、旧 blue 環境は -old1 が付いた状態で残ります。放っておくと課金が続くので削除しますが、削除は切り戻しの選択肢を捨てる操作です。今回は切り替え後の動作をしばらく確認してから削除しました。

手順は次のとおりです。

  1. 旧環境(-old1)を選択して削除。削除保護が有効な場合は、先に「変更」から無効にする
  2. あわせてブルー/グリーンデプロイ定義も削除する

念のため削除時に最終スナップショットを取得しておくと、後から戻したくなったときの保険になります。

切り戻しについて

何かあった場合の切り戻しに関してですが、Blue/Green Deployments に「切り替えを戻すボタン」はありません。 切り替え後、旧環境(-old1)は読み取り専用で残りますが、新環境からの逆レプリケーションは張られないため、レコードの更新が入ると乖離が生じていきます。

では、切り替え中のリスクは何か?公式ドキュメントによると次の2点です。

  • 書き込み(INSERT / UPDATE / DELETE) … 切り替え中は blue が read-only になるため、1290 (HY000) --read-only で弾かれる可能性がある
  • 切り替え中に張ろうとした新規接続 … 読み書きを問わず失敗する可能性がある

参照(SELECT)は基本的に止まりません。
今回は書き込みがほとんど走らない時間帯を選んでおり、実際のダウンタイムも約1秒とごく僅かだったので、エラーも表面化しませんでした。

どうしても旧環境に書き戻す必要が生じた場合、read_only を無効(0)にして再起動する必要がありますが、default.mysql8.0 のようなデフォルトパラメータグループでは read_only を変更できません。そのため、切り戻しの余地を残すなら切り替え前にカスタムパラメータグループを用意しておきます。今回も事前に作成しておきました。

RDSBlueGreenParameterGroup.png

旧環境を削除済みの場合は、アップグレード前に取得したスナップショットからの復元が最後の手段になります。いずれにせよ切り替え直後の確認が勝負で、時間が経つほど戻せなくなります。

まとめ

冗長化していない Single-AZ の本番 RDS MySQL のメジャーアップグレードを実施しました。

Blue/Green Deployments を活用することで、書き込みダウンタイム約1秒でアップグレードできました。

切り替えの際のエンドポイントは自動で引き継いでくれるので、アプリ側の変更が無いのは便利でした。一方で、自動ロールバックが無いため、切り替え直後の動作確認は迅速に行う必要があります。

安全を期すのであれば、基本的なことにはなりますが、どの方式を選択するにしてもやはり一定期間のダウンタイムを設けた方が賢明だと思いました。その前提で Blue/Green を採用することで、手間なく安全な切り替えを進められそうです。

参考

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?