EC2 Classic から VPC へのオンラインマイグレーション

先月、ラスベガスで開催された re:Invent 2014 のセッションの中でさらっと [VPC ClassicLink](http://www.slideshare.net/AmazonWebServices/sdd422-amazon-vpc-deep-dive-aws-reinvent-2014) なる機能が発表され、すでに賞味期限切れ感のある内容ですが、せっかくなのでまとめておきます。

## 背景

- 移行以前は EC2 Classic と VPC が混在
    - EC2 Classic と VPC 間の通信はセキュリティグループで制御
- 移行するモチベーション 
    - VPC でないとできないことが増えつつある (例: T2 インスタンス)
    - セキュリティグループが煩雑になりがち

## 移行するコンポーネント

- Amazon EC2 (web/app)
- Amazon RDS (master & slaves)
- Amazon ElastiCache

ElastiCache はキャッシュとしてしか使っておらず、単に両書きすればよいだけだったので、今回の話からは省略します。(なお、簡略化のため ELB なども省略してます) 参考までに移行前の構成を図にしておきます。

![migration-01.png](https://qiita-image-store.s3.amazonaws.com/0/1915/d616d87b-b600-88b4-5746-8784e89162fb.png)

## 1. RDS のレプリケーションをセットアップ

とりあえず VPC 側に RDS を用意して、EC2 Classic の RDS からレプリケーションを組みます。やり方は "[Using Replication to Export MySQL 5.6 Data - Amazon Relational Database Service](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MySQL.Procedural.Exporting.NonRDSRepl.html)" や、"[Replication with a MySQL Instance Running External to Amazon RDS - Amazon Relational Database Service](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MySQL.Procedural.Importing.External.Repl.html)" を参考にしましたが、簡単にまとめておくと下記のような流れです。

- old-master (EC2 Classic の master) で下準備
    - binlog の retention hour を 24 hour に変更
    - repl ユーザを作る
    - リードレプリカを作成
        - stop slave して、show slave status の結果を控える
        - mysqldump を取得
- new-master (VPC 内の master 昇格候補) を用意
    - old-master や web/app から接続できるようにセキュリティグループを設定
    - 先ほど取得した mysqldump を流し込む
    - dump 時の情報を元に `mysql.rds_set_external_master` する
    - `mysql.rds_start_replication` でレプリケーションを開始
    - new-master のリードレプリカ作成、old-master のリードレプリカを削除
- web/app の参照先を切り替え
    - VPC 内のリードレプリカを参照するよう変更

![migration-02.png](https://qiita-image-store.s3.amazonaws.com/0/1915/2cd0f67b-b750-40fe-6187-aa8f3ab62092.png)

なお、EC2 Classic の EC2 から VPC の RDS にアクセスするため、EC2 インスタンスの Pubilic IP をセキュリティグループに追加する必要がありましたが、これはプルリクベースでセキュリティグループの管理ができる [Piculet](https://github.com/winebarrel/piculet) にお世話になりました。

## 2. RDS のマスタを切り替え

1 の手順で、すでにアプリからの参照先は VPC 内の RDS を向いているので、マスタを切り替えていきます。タイトルにオンラインマイグレーションと書きましたが、正確には DB を readonly にしてマスタ切り替えという流れになるので、深夜に 1 分程度、アプリの設定変更が行えない (ユーザへの影響は軽微) 状態になっています。

やることは DB を readonly にした上で、更新先を new-master に切り替え、new-master で `call mysql.rds_start_replication;` と `call mysql.rds_reset_external_master;` をした上で、readonly を解除するだけです。

ここまで来れば、移行はほぼ終わりです。

![migration-03.png](https://qiita-image-store.s3.amazonaws.com/0/1915/dc07d867-fcb9-671e-5462-9bdff610e9d4.png)

## 3. アプリサーバの移行

VPC 内にアプリサーバを立ち上げ、[Route53 の Weighted Routing] (http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html) で DNS の参照比率を変更していきました。

![migration-04.png](https://qiita-image-store.s3.amazonaws.com/0/1915/7cad2b0b-ce26-4e02-6742-3496578a9387.png)

EC2 Classic のインスタンスに `Env=classic`、VPC のインスタンスに `Env=vpc` みたいなタグをつけておくと、Datadog でこのようなグラフが簡単に作れ、CPU 使用率やエラー数などを環境毎に確認しながら作業を進めることで、安心して作業が進められました。

![web_datadog.png](https://qiita-image-store.s3.amazonaws.com/0/1915/774c6159-d80e-9f1a-6dde-b6b2c49bc47b.png)

## 4. EC2 Classic 環境を削除

旧環境への参照がなくなったところで、EC2 Classic のインスタンスをお片付けして完了です。

![migration-05.png](https://qiita-image-store.s3.amazonaws.com/0/1915/def6b298-abb1-2722-5a4e-672cb0d8f799.png)

## まとめ

ということで、無事に EC2 Classic から VPC への移行が完了したというお話でした。めでたしめでたし。