運用中のサービスに与える影響を最小限に抑えつつ、EC2-Classic上のRDSをVPC上に移行する

たまチームで開発しているWebサービスの大半は AWS EC2-Classic 上で動いているのだが、去年から標準でサポートされるようになった VPC (Virtual Private Cloud) に移行しないといろいろと不便なことが多くなってきた。というわけで、移行にあたって一番厄介だと思われる RDS の移行手順を以下にまとめた。

ちなみにこの手順は、EC2-Classic から VPC への移行だけでなく、VPC から VPC の移行にも適用出来るはず。

rds-migration1

大まかな流れとしては、

  1. リードレプリカ経由でClassic側のdumpを取り
  2. それをVPC側で復元
  3. 復元したデータベースをClassic側のslaveとして動かしてデータを同期
  4. 読み込み専用のアプリはここでVPC側に移行して動作確認
  5. VPC側をmasterに昇格した後(ここで一瞬だけ Read Only になる)
  6. 書き込みのあるアプリケーションもVPC側に切り替えて
  7. Classic側を潰せば

めでたく移行は完了する。

1. リードレプリカ経由でClassic側のdumpを取る

rds-migration2

まずはClassic側で移行用のdumpを取得する。リードレプリカを作ってすぐにリプリケーションを停止し、そのときのdumpとバイナリログの位置を取得しておく。リードレプリカ経由なので、この間、サービスの運用には一切影響を与えない。

バイナリログの保持期間を変更する

デフォルトのバイナリログの保持期間が短いので、VPC-slaveを作る間にログが消失してしまわないよう、Classic-masterで以下のように変更しておく。

CALL mysql.rds_set_configuration('binlog retention hours', 24);

現在の設定を確認する:

CALL mysql.rds_show_configuration;

レプリケーション用のユーザーを作る

Classic-masterでレプリケーション用のユーザーを作っておく。

GRANT REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'repl_user' IDENTIFIED BY 'some-password';

Classic-masterのリードレプリカを作る

AWS管理コンソールで Classic-master となるRDSインスタンスを選び、”Instance Actions” から “Create Read Replica” を選択する。

レプリケーションをストップする

Classic-slave(今作ったレプリカ)のレプリケーションをストップする。

CALL mysql.rds_stop_replication;

バイナリログの位置を記録する

Classic-slaveで、レプリケーションの状態をメモる(どの位置からレプリケーションを再開すれば良いか)。

show slave statusG
...
    Master_Log_File: mysql-bin-changelog.050354
Read_Master_Log_Pos: 422
...
   Slave_IO_Running: No
  Slave_SQL_Running: No
...

Slave_IO_RunningSlave_SQL_RunningNoになっているので、ちゃんとレプリケーションが止まっていることが分かる。

Classic-slaveのdumpを取る

  • Classic-slaveのエンドポイントを classic-slave.rds.amazonaws.com、管理ユーザーを dbuser とする。
mysqldump -u dbuser -h classic-slave.rds.amazonaws.com --single-transaction --compress --order-by-primary --max_allowed_packet=1G -p --databases database1 databases2  > classic-slave.dump

2. VPCにClassic-masterのレプリカを作る

rds-migration3

VPC内に立てたRDSインスタンスに、Classic-slaveのdumpをインポートしてClassic-masterへのレプリケーションを再開させる(VPC-slave)。

VPC-slaveとなるRDSインスタンスを立ち上げる

AWS管理コンソールでサクッと立ち上げる。

VPC-slaveにClassic-slaveのdumpをインポート

  • VPC-slaveのエンドポイントを vpc.rds.amazonaws.com、管理ユーザーを dbuser とする。
mysql -u dbuser -h vpc.rds.amazonaws.com -p --default-character-set=utf8 < classic-slave.dump

Classic-masterのセキュリティグループ設定を変更する

レプリケーションを可能にするために、VPC-slave から Classic-master にアクセス出来るようにセキュリティグループ(DB Security Groups)を設定する。

以下のような感じで VPC-slave のIPを調べて、そのIPからのアクセスを許可する:

$ ping vpc.rds.amazonaws.com

以下を Classic-master のセキュリティグループに追加。

CIDR/IP to Authorize:  xxx.xxx.xxx.xxx/32

レプリケーションをスタートさせる

VPC-slave にログインして、レプリケーションをスタートさせる(さっき作った専用ユーザーがここで活躍)。
パラメータは先ほどメモしたレプリケーションの状態を参考に。

CALL mysql.rds_set_external_master('classic-master.rds.amazonaws.com',3306,'repl_user','some-password','mysql-bin-changelog.050354',422,0);
CALL mysql.rds_start_replication;

レプリケーションの状態を確認:

show slave statusG

以下のような項目があれば、正しくレプリケーションが動作している。

...
 Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...

レプリケーションがうまく行ったら、Classic-slaveは用無しなので削除する。
この段階で読み込み専用のアプリはVPC内に移行出来る。

3. VPC-slaveをmasterに昇格する

rds-migration4

Classic-masterをReadOnlyにする

FLUSH TABLES WITH READ LOCK;

Closes all open tables and locks all tables for all databases with a global read lock. This is a very convenient way to get backups if you have a file system such as Veritas or ZFS that can take snapshots in time. Use UNLOCK TABLES to release the lock.

として、全てのテーブルをロックしてから切り替えたいところなのだが、RDSではこの命令を実行するための権限がないことが判明。

簡単な代替策もないようなので、とりあえず編集を行う可能性があるサービスを全て「メンテナンス中」として操作出来ないようにした。

VPC-slaveのレプリケーションを停止する

CALL mysql.rds_stop_replication;
CALL mysql.rds_reset_external_master;

以後、こちらを master として扱う。

アプリケーションをVPC内に移動する

VPC内にアプリケーションサーバーを立てて、そちらを指すようにDNSの設定を書き換える。

後は古いClassic環境を潰して移行は完了。