AWS CloudFormationで管理しているAmazon RDS for MySQLからAmazon Aurora MySQLに移行する手順を整理した

こんにちは。サービスグループの武田です。AWS CloudFormationで管理しているAmazon RDS for MySQLデータベースからAmazon Aurora MySQLへの移行パスを整理してみました。
2020.07.07

こんにちは。サービスグループの武田です。

Amazon RDS for MySQLデータベースからAmazon Aurora MySQLへの移行パスはいくつか用意されています。それではAWS CloudFormation(以下、CFn)で管理をしている場合はどうでしょうか。このエントリではその手順を整理してみました。

Aurora移行時に検討すべき事項

Auroraは非常に堅牢な、AWSのマネージドRDBサービスです。MySQL互換およびPostgreSQL互換のAuroraが提供されていますが、今回はMySQL互換を対象としています。

MySQL互換 ということで、アプリケーションやツールは差異を意識せずに使用できますが、MySQLのすべての機能を備えているわけではありません。例を挙げると、MyISAMストレージエンジンなど特定の機能が使えないことや、指定できないパラメーターが存在したりします。これらはドキュメントに記載されているため、しっかりと確認しましょう。もちろん、実際にAuroraを構築してアプリケーションを稼働させてみることも重要です。

移行手順の整理

さてデータベースの移行ですが、次の2ステップに分けて整理するのがよさそうです。

  1. RDSからAuroraへのデータコピー
  2. AuroraクラスターとCFnテンプレートの同期

データコピーについては次の方法が考えられます。

  • スナップショット作成/リストア
  • リードレプリカ作成

スナップショットを利用した移行はリストアが完了するまで停止点が必要です。一方でリードレプリカを使用する方法はスナップショットに比べてシステムの停止時間を小さくできます。

次にAuroraクラスターとCFnテンプレートの辻褄を合わせることを考えます。これも次の方法が考えられます。

  • リストアするスナップショットをCFnテンプレートで指定する
  • 構築したAuroraクラスターをCFnスタックにインポートする

以上のことを整理すると、移行パスは次のものが考えられます。

  1. 既存のDBからスナップショットを作成し、それをSnapshotIdentifierに指定した新しいAuroraクラスターをCFnで作成する
  2. 既存のDBからスナップショットを作成しリストアしてAuroraクラスターを構築。それをCFnスタックにインポートする
  3. 既存のDBのリードレプリカをAuroraで作成し、それをCFnスタックにインポートする

CFnのインポート機能がなかった時代はおそらく1しか方法がなかったのではないかと想像します。将来はどうなるか分かりませんが、今なら3の方法が簡単そうです。というわけで、前置きが長くなりましたが、整理した3の方法を実際にやってみました。

手順は次のとおりです。

  1. CFnでDBインスタンスを構築
  2. リードレプリカをAuroraクラスターで作成(手作業)
  3. リードレプリカを昇格(手作業)
  4. AuroraクラスターをCFnスタックにインポート(手作業)
  5. CFnを更新してDBインスタンスを削除

移行元となるDBインスタンスの作成

まずはシンプルな構成のDBインスタンスを1台構築します。これが移行元となるデータベースになります。次のCFnテンプレートから始めましょう。SubnetGroupのSubnetIdsやDBDNSRecordのHostedZoneIdなどは実際の環境に合わせて修正してください。

rds.template.yml

Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    DeletionPolicy: Snapshot
    Properties:
      AllocatedStorage: '5'
      DBInstanceClass: db.t3.medium
      DBParameterGroupName: !Ref DBParameterGroup
      DBSubnetGroupName: !Ref DBSubnetGroup
      Engine: MySQL
      EngineVersion: 5.7.30
      MasterUsername: admin
      MasterUserPassword: your_secret
      StorageType: gp2

  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: custom subnet group
      SubnetIds:
        - subnet-aaaaaaa
        - subnet-bbbbbbb
        - subnet-ccccccc

  DBParameterGroup:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Description: custom paramter group
      Family: MySQL5.7
      Parameters:
        character_set_database: utf8mb4
        character_set_client: utf8mb4
        character_set_connection: utf8mb4
        character_set_results: utf8mb4
        character_set_server: utf8mb4

  DBDNSRecord:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneId: ABCDEFGHIJKLMN
      Name: db.example.com
      Type: CNAME
      TTL: 60
      ResourceRecords:
        - !GetAtt DBInstance.Endpoint.Address

DBインスタンスおよび参照用に、Route 53にCNAMEレコードを追加しています。このように名前を与えておくことで、Auroraに切り替えてもアプリケーションからは同じ名前でDBにアクセスできます。テンプレートが用意できたらスタックを作成します。

$ aws cloudformation create-stack --template-body file://rds.template.yml --stack-name rds-update-test

しばらく待っているとDBインスタンスなどが作成されます。

Route 53のレコードも作成されています。

Auroraでリードレプリカを作成

DBインスタンスが用意できたので、次はAuroraクラスターを構築します。今回は先ほど構築したDBインスタンスのリードレプリカとして構成することで、自動的にデータが同期されるようにします。またクラスターを昇格するまでは自動的にレプリケーションされるため、任意のタイミングで構築できます。切り替えは計画メンテナンスの時間で行うが、リードレプリカの作成は事前に作成といったことが可能です。

リードレプリカの作成はマネジメントコンソールから簡単に行えます。作成されたDBインスタンスの詳細画面から、[アクション] > [Aurora リードレプリカの作成]を選択します。

リードレプリカの仕様を選択します(デフォルト部分は省略します)。

エンジンのバージョンはとりあえず現時点での最新を選びました。インスタンスクラスは先ほど作成したDBインスタンスに合わせました。

識別子を入力します。今回はmydbinstanceとしました。

VPCなどはデフォルトとしていますが、サブネットグループは先ほどCFnで作成したものを選択しています。この辺は実際の環境に合わせましょう。

必要事項を選択できたらリードレプリカを作成します。待つこと30分程度でリードレプリカが作成されました。

RDSからAuroraへの移行作業

それでは準備が整いましたので、実際にAuroraへ切り替える移行作業をしていきましょう。

まずはAuroraクラスターがリードレプリカとして構成されているため、スタンドアローンに昇格させます。この作業以降、DBの同期は切れますので注意しましょう。Auroraクラスターを選択し、[アクション] > [昇格]を選択します。昇格自体は数分で完了します。

DBインスタンスのロールが マスター から インスタンス に変わればOKです。

続いてAuroraクラスターをCFnスタックにインポートします。マネジメントコンソールでCFnのスタックのページを開き、[スタックアクション] > [スタックへのリソースのインポート]を選択します。

インポートするためのテンプレートをアップロードします。

先ほど作成したCFnテンプレートにAuroraクラスターを追加したテンプレートを用意します。ポイントは「インポートだけ」をすることです。クラスターのパラメーターグループ追加や、DNSレコードの更新は次のステップで行います。

@@ -13,6 +13,35 @@
       MasterUserPassword: your_secret
       StorageType: gp2

+  DBCluster:
+    Type: AWS::RDS::DBCluster
+    DeletionPolicy: Retain
+    Properties:
+      DBClusterParameterGroupName: default.aurora-mysql5.7
+      DBSubnetGroupName: !Ref DBSubnetGroup
+      Engine: aurora-mysql
+      EngineVersion: 5.7.mysql_aurora.2.08.1
+      MasterUsername: admin
+      MasterUserPassword: your_secret
+
+  DBWriterInstance:
+    Type: AWS::RDS::DBInstance
+    DeletionPolicy: Retain
+    Properties:
+      DBClusterIdentifier: !Ref DBCluster
+      DBInstanceClass: db.t3.medium
+      DBSubnetGroupName: !Ref DBSubnetGroup
+      Engine: aurora-mysql
+
+  DBReaderInstance:
+    Type: AWS::RDS::DBInstance
+    DeletionPolicy: Retain
+    Properties:
+      DBClusterIdentifier: !Ref DBCluster
+      DBInstanceClass: db.t3.medium
+      DBSubnetGroupName: !Ref DBSubnetGroup
+      Engine: aurora-mysql
+
   DBSubnetGroup:
     Type: AWS::RDS::DBSubnetGroup
     Properties:

このテンプレートをアップロードして進めると、インポートするリソースを指定する画面となります。実際のAuroraクラスターの名前を確認しながら「識別子の値」をそれぞれ埋めます。

問題なければ「変更」としてリソースが認識されます。[リソースをインポート]ボタンをポチッと押しましょう。

無事にスタックに取り込まれたようです。

最後の仕上げとして最終形のCFnテンプレートを用意し、スタックを更新しましょう。

@@ -1,23 +1,9 @@
 Resources:
-  DBInstance:
-    Type: AWS::RDS::DBInstance
-    DeletionPolicy: Snapshot
-    Properties:
-      AllocatedStorage: '5'
-      DBInstanceClass: db.t3.medium
-      DBParameterGroupName: !Ref DBParameterGroup
-      DBSubnetGroupName: !Ref DBSubnetGroup
-      Engine: MySQL
-      EngineVersion: 5.7.30
-      MasterUsername: admin
-      MasterUserPassword: your_secret
-      StorageType: gp2
-
   DBCluster:
     Type: AWS::RDS::DBCluster
     DeletionPolicy: Retain
     Properties:
-      DBClusterParameterGroupName: default.aurora-mysql5.7
+      DBClusterParameterGroupName: !Ref AuroraClusterParameterGroup
       DBSubnetGroupName: !Ref DBSubnetGroup
       Engine: aurora-mysql
       EngineVersion: 5.7.mysql_aurora.2.08.1
@@ -51,11 +37,11 @@
         - subnet-8b9b60c2
         - subnet-52d9877a

-  DBParameterGroup:
-    Type: AWS::RDS::DBParameterGroup
+  AuroraClusterParameterGroup:
+    Type: AWS::RDS::DBClusterParameterGroup
     Properties:
-      Description: custom paramter group
-      Family: MySQL5.7
+      Description: custom cluster paramter group
+      Family: aurora-mysql5.7
       Parameters:
         character_set_database: utf8mb4
         character_set_client: utf8mb4
@@ -71,4 +57,14 @@
       Type: CNAME
       TTL: 60
       ResourceRecords:
-        - !GetAtt DBInstance.Endpoint.Address
+        - !GetAtt DBCluster.Endpoint.Address
+
+  DBReadDNSRecord:
+    Type: AWS::Route53::RecordSet
+    Properties:
+      HostedZoneId: ABCDEFGHIJKLMN
+      Name: db-ro.example.com
+      Type: CNAME
+      TTL: 60
+      ResourceRecords:
+        - !GetAtt DBCluster.ReadEndpoint.Address

やっていることは次のことです。

  • DBインスタンスおよびカスタムパラメーターグループの削除
  • Auroraクラスター用のカスタムパラメーターグループ作成およびクラスターへの適用
  • db.example.comのレコードを修正
  • db-ro.example.comのレコードを追加

それではスタックを更新します。

$ aws cloudformation deploy --template-file rds.template.yml --stack-name rds-update-test

しばらく待つとDBインスタンスの削除なども含めスタックの更新が完了します。Route 53の画面を確認してみると、レコードも更新されています。

まとめ

マネジメントコンソールやCLIを使うことで簡単にRDSの移行も行えます。ところがCFnが絡むと考えることが多くなって難易度が上がるように思えます。とはいえ、実際に検証してみることで手順も確認できますので、皆さんも気になることはどんどん試してみてください。