Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)

Akatsuki Hackers Labは株式会社アカツキが運営しています。

CloudFormationでAuroraのMySQL5.7インプレースアップグレードをする際のハマりポイント&対応方法

Amazon Aurora MySQL のインプレースアップグレード機能

つい先日、Amazon Aurora にて、MySQL 5.6互換のバージョン1.xから、MySQL 5.7互換のバージョン2.xへインプレースアップデートが可能になりました。

Amazon Aurora が MySQL 5.6 から 5.7 へのインプレースアップグレードをサポート

この機能を使うことで、従来のようにスナップショットからの復元やレプリケーション、インスタンスの切替といった作業をしなくても、エンドポイントなどはそのままに、簡単にMySQL5.7互換にアップグレードすることが可能になります。

早速この機能でアップグレードを試みたのですが、CloudFormationで管理されているAuroraクラスターをアップグレードする際にちょっとハマったことがあったので、その内容と対応方法をシェアします。

アップデート前のRDS用CloudFormation stack

更新前のDBクラスタのCloudFormationでの定義はこんな感じでした。(わかりやすいよう最小限の記述のみにしてあります)

DevAuroraParameterGroup というカスタムのインスタンスパラメータグループを使っています。

---
AWSTemplateFormatVersion: '2010-09-09'
Description: RDS for sandbox
Resources:
  DevAuroraParameterGroup:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Description: Development Aurora parameter group
      Family: aurora5.6
      Parameters:
        max_connections: '1024'
        wait_timeout: '300'
  DevAuroraParameterGroup57:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Description: Development Aurora parameter group for 5.7
      Family: aurora-mysql5.7
      Parameters:
        max_connections: '1024'
        wait_timeout: '300'
  DBCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DBClusterIdentifier: test-cluster
      DBSubnetGroupName:
        Fn::ImportValue: DBSubnetGroup
      Engine: aurora
      EngineVersion: 5.6.mysql_aurora.1.22.2
      MasterUsername: "{{resolve:ssm:rds.username.default:1}}"
      MasterUserPassword: "{{resolve:ssm-secure:rds.password.default:1}}"
  DBInstance:
    Type: AWS::RDS::DBInstance
    DeletionPolicy: Delete
    Properties:
      DBClusterIdentifier:
        Ref: DBCluster
      DBInstanceClass: db.t2.medium
      DBInstanceIdentifier: test-db
      Engine: aurora
      EngineVersion: 5.6.mysql_aurora.1.22.2
      DBParameterGroupName:
        Ref: DevAuroraParameterGroup
      DBSubnetGroupName:
        Fn::ImportValue: DBSubnetGroup

ハマったこと

これを、以下のように書き換えて適用することで、MySQL5.7互換バージョンへのインプレースアップグレードを試みます。

@@ -82,8 +82,8 @@
       DBClusterIdentifier: test-cluster
       DBSubnetGroupName:
         Fn::ImportValue: DBSubnetGroup
-      Engine: aurora
-      EngineVersion: 5.6.mysql_aurora.1.22.2
+      Engine: aurora-mysql
+      EngineVersion: 5.7.mysql_aurora.2.07.3
       MasterUsername: "{{resolve:ssm:rds.username.default:1}}"
       MasterUserPassword: "{{resolve:ssm-secure:rds.password.default:2}}"
   DBInstance:
@@ -94,9 +94,9 @@
         Ref: DBCluster
       DBInstanceClass: db.t2.medium
       DBInstanceIdentifier: test-db
-      Engine: aurora
-      EngineVersion: 5.6.mysql_aurora.1.22.2
+      Engine: aurora-mysql
+      EngineVersion: 5.7.mysql_aurora.2.07.3
       DBParameterGroupName:
-        Ref: DevAuroraParameterGroup
+        Ref: DevAuroraParameterGroup57
       DBSubnetGroupName:
         Fn::ImportValue: DBSubnetGroup

しかし、以下のようなエラーで失敗してしまいました。

{
  "LogicalResourceId": "DBCluster",
  "ResourceStatus": "UPDATE_FAILED",
  "ResourceStatusReason": "The current DB instance parameter
     group sandbox-rds-devauroraparametergroup-fxfe7dqcn31p
     is custom. You must explicitly specify a new DB instance
     parameter group, either default or custom, for the engine
     version upgrade. (Service: AmazonRDS; Status Code: 400; Error Code: InvalidParameterCombination; Request ID: ...)"
}

カスタムのインスタンスパラメータグループを使っているため、5.7に対応した新しい DevAuroraParameterGroup57 に切り替えるよう指定しなければなりません。 CLIであれば modify-db-cluster--db-instance-parameter-group-name オプションでこれを指定可能です。 しかし、どうやらCloudFormationではこれを渡すことができない様子です。同時に DBInstance の更新をしても、異なるリソースの変更までは拾ってはくれないようです。。

対応方法その1

こういう時の一つの方法は、いったんCloudFormationの管理下から外してしまい、手動でアップデートしたのち、CloudFormationにインポートし直すという方法です。

  1. DBCluster および DBInstanceDeletionPolicy: Retain を指定して適用することで、CloudFormationによってこれらが削除されないようにします。

  2. DBCluster および DBInstance の定義を削除し、更新を行います。

  3. 残ったクラスターをAWSコンソールで5.7に更新します。

  4. 5.7の定義で再度 DBCluster および DBInstance の定義を追加し、「インポート」 を行います。この時、追加する各リソースに対応するインスタンスの識別子(ここでは test-clustertest-db )を指定することで、CloudFormationスタックに既存リソースを取り込むことが可能です。

  5. ドリフト検知を行い、定義と実態にズレがないことを確認します。

しかし、手動オペレーションはなるべく避けたいということで、次のような方法も考えてみました。

対応方法その2

エラーメッセージを見るに、カスタムのインスタンスパラメータグループを使わなければ良いのだろうということで、いったんデフォルトに戻し、インブレースアップグレード後に再びカスタムのパラメータを適用しなおしてみます。

まず、 DBInstance のパラメータグループをデフォルトである default.aurora5.6 にしてスタックを更新します。

@@ -96,7 +96,6 @@
       DBInstanceIdentifier: test-db
       Engine: aurora
       EngineVersion: 5.6.mysql_aurora.1.22.2
-      DBParameterGroupName:
-        Ref: DevAuroraParameterGroup
+      DBParameterGroupName: default.aurora5.6
       DBSubnetGroupName:
         Fn::ImportValue: DBSubnetGroup

次に、 インプレースアップグレードと合わせて、新しいカスタムのパラメータグループも指定して再度更新します。

@@ -82,8 +82,8 @@
       DBClusterIdentifier: test-cluster
       DBSubnetGroupName:
         Fn::ImportValue: DBSubnetGroup
-      Engine: aurora
-      EngineVersion: 5.6.mysql_aurora.1.22.2
+      Engine: aurora-mysql
+      EngineVersion: 5.7.mysql_aurora.2.07.3
       MasterUsername: "{{resolve:ssm:rds.username.default:1}}"
       MasterUserPassword: "{{resolve:ssm-secure:rds.password.default:2}}"
   DBInstance:
@@ -94,8 +94,9 @@
         Ref: DBCluster
       DBInstanceClass: db.t2.medium
       DBInstanceIdentifier: test-db
-      Engine: aurora
-      EngineVersion: 5.6.mysql_aurora.1.22.2
-      DBParameterGroupName: default.aurora5.6
+      Engine: aurora-mysql
+      EngineVersion: 5.7.mysql_aurora.2.07.3
+      DBParameterGroupName:
+        Ref: DevAuroraParameterGroup57
       DBSubnetGroupName:
         Fn::ImportValue: DBSubnetGroup

これで、無事にCloudFormationのみでインプレースアップグレードが完了しました。 またMySQL5.7への移行完了後も、DBは問題なく利用できることを確認できました。

後者の方法は途中でパラメータグループの更新が余分に入るという欠点がありますが、対象が多くて自動化したい場合などはこちらの手段の方が良いこともあるかもしれません。

もっとうまく対応できる方法が提供されるとありがたいのですけれどね。