mazyu36の日記

某SIer所属のクラウドエンジニアのブログ

AWS CDKで作ったAurora グローバルデータベースは運用できるのか

-----(2024/3/25追記) -----

本記事の内容は古いです。2024年時点では本記事のように「計画外フェイルオーバー」時にクラスターの切り離し作業などが不要です。

詳細は以下をご覧ください。

mazyu36.hatenablog.com

----- 追記ここまで -----

リージョン間フェイルオーバーを行うため、Auroraグローバルデータベースを検討することはあるかと思います。

※Aurora グローバルデータベース:リージョン間でデータをレプリケートし、リージョンを跨って運用するための仕組み。

https://pages.awscloud.com/rs/112-TZM-766/images/ORL-T4-Session.pdf

Primaryのリージョンを切り替える際に当然フェイルオーバー操作が発生します。このフェイルオーバー操作がIaCとはなんとも相性が悪そうです。

今回はAWS CDKでAuroraグローバルデータベースを構築したとして、フェイルオーバー発動後にCDKの設定変更反映など運用継続ができるのか?を検証してみました。

結論としては「運用可能」と思われます。以下詳細が続きます。

前提

グローバルデータベースにおけるフェイルオーバーは2つ存在します。AWS公式の用語を参考にここでは以下の用語を用いることにします。

  • 計画内フェイルオーバー:PrimaryクラスターとSecondaryクラスターを入れ替えるだけのフェイルオーバー。運用メンテナンスなど、計画した上で行うもの。
  • 計画外フェイルオーバー:Secondaryクラスターをグローバルデータベースから切り離し、昇格させるフェイルオーバー。災害でPrimaryクラスターが使えなくなった場合などに行うもの。

docs.aws.amazon.com

計画外フェイルオーバーの手順は以下が詳しくまとまっていました。Secondaryクラスターを切り離して昇格、その後再度グローバルデータベースを構築し直して復旧という形になります。

qiita.com

グローバルデータベースのCDK実装

まず初期構築として、東京リージョンをPrimary、大阪リージョンをSecondaryとするグローバルデータベースを構築してみます。

一部コツが入りますが、構築すること自体はそこまで難しくありません。

Stackの実装

リージョンが違うので、Stackを分ける必要があります。以下のようにStackの定義においてregionを明示します。

new PrimaryStack(app, 'PrimaryStack', {
  env: {
    region: 'ap-northeast-1'
  }
});

new SecondaryStack(app, 'SecondaryStack', {
  env: {
    region: 'ap-northeast-3'
  }
});

東京リージョンのPrimaryクラスターとGlobalDatabaseの実装

以下東京リージョンのAuroraクラスター(Primary)の実装例です。

// DBクラスターを作成
this.dbCluster = new rds.DatabaseCluster(scope, 'Database', {
  engine: rds.DatabaseClusterEngine.auroraMysql({
    version: rds.AuroraMysqlEngineVersion.VER_3_01_0
  }),
  clusterIdentifier: 'test-aurora-tokyo',
  // credentialを自動生成。usernameのみadminを指定
  credentials: {
    username: 'admin',
    secretName: 'dbSecret'
  },
  instances: 1,
  instanceProps: {
    vpc: props.vpcConstruct.vpc,
    instanceType: ec2.InstanceType.of(InstanceClass.R5, InstanceSize.LARGE),
    publiclyAccessible: false,
    deleteAutomatedBackups: false,
    securityGroups: [props.securityGroupConstruct.databaseSg],
    vpcSubnets: {
      subnets: [props.vpcConstruct.subnetDB1a, props.vpcConstruct.subnetDB1c],
    }
  },
  port: 3306,
  defaultDatabaseName: 'test',
  subnetGroup: dbSubnetGroup,
  backup: {
    retention: cdk.Duration.days(1)
  },
  storageEncrypted: false,
  removalPolicy: cdk.RemovalPolicy.DESTROY
})

// グローバルデータベースを作成
new rds.CfnGlobalCluster(scope, 'GlobalDatabase', {
  deletionProtection: false,
  globalClusterIdentifier: 'test-global-database',
  sourceDbClusterIdentifier: this.dbCluster.clusterIdentifier // Primaryクラスターの識別子を指定
})

PrimaryのAuroraクラスターは通常と同様で特別なことはしていません。暗号化は一旦行わない形としています。

グローバルデータベースはCfnGlobalClusterを使用して作成します。

ここではsourceDbClusterIdentifierとしてPrimaryクラスターの識別子を指定することで、東京リージョンをPrimaryとするグローバルデータベースの作成を行っています。

大阪リージョンのSecondaryクラスターの実装

以下が実装例です。ポイントとなる箇所にコメントをつけています。

this.dbCluster = new rds.DatabaseCluster(scope, 'Database', {
  engine: rds.DatabaseClusterEngine.auroraMysql({
    version: rds.AuroraMysqlEngineVersion.VER_3_01_0
  }),
  clusterIdentifier: 'test-aurora-osaka',
  instances: 1,
  instanceProps: {
    vpc: props.vpcConstruct.vpc,
    instanceType: ec2.InstanceType.of(InstanceClass.R5, InstanceSize.LARGE),
    publiclyAccessible: false,
    deleteAutomatedBackups: false,
    securityGroups: [props.securityGroupConstruct.databaseSg],
    vpcSubnets: {
      subnets: [props.vpcConstruct.subnetDB1a, props.vpcConstruct.subnetDB1c],
    }
  },
  port: 3306,
  // defaultDatabaseName: 'test',  // PrimaryClusterのものを引き継ぐので未設定にする。
  subnetGroup: dbSubnetGroup,
  backup: {
    retention: cdk.Duration.days(1)
  },
  storageEncrypted: false,
  removalPolicy: cdk.RemovalPolicy.DESTROY
})

// Escape Hatchesを使用して設定。
const cfnCluster = this.dbCluster.node.defaultChild as rds.CfnDBCluster;
// グローバルデータベースセカンダリとするための設定を実施
cfnCluster.masterUsername = undefined;
cfnCluster.masterUserPassword = undefined;
cfnCluster.globalClusterIdentifier = 'test-global-database'
}

SecondaryではPrimaryから引き継ぐ箇所は未設定とすること、またグローバルデータベースが何かを設定する必要があります。

特に以下の項目はL2 Constructからは直接いじれないので、Escape Hatchesを使用して編集する必要があります。

  • masterUsername, masterPassword:Primaryから引き継ぐために未設定にする。
  • globalClusterIdentifier:グローバルデータベースの識別子を指定する。スタック間参照で設定しても良いですが、ただの文字列なので今回は直接指定しました。

これにより以下のような東京をPrimary、大阪をSecondaryとするAuroraグローバルデータベースを構築できました。

フェイルオーバー動作検証

フェイルオーバーですが手順を見る限りでは全てをCDK上で再現させるのは困難(というか無理?)かと思います。

そのためここでは手動でフェイルオーバーさせた後、CDK上による設定変更の反映など運用を維持し続けられるのかを検証します。

以下の3パターン検証します。

  • ①計画内フェイルオーバー実施後、実態とCDKがずれた状態でCDK上の設定変更を反映できるか
  • ②計画外フェイルオーバー実施後、実態とCDKがずれた状態でCDK上の設定変更を反映できるか
  • ③計画外フェイルオーバー実施後、手動で実態とCDKを一致させた状態でCDK上の設定変更を反映できるか

①計画内フェイルオーバー実施後、実態とCDKがずれた状態でCDK上の設定変更を反映できるか

ここでやりたいことは以下です。

  • マネコン上で計画内フェイルオーバーを行い、Primaryを大阪、Secondaryを東京にする。この時CDK上では東京Primary、大阪Secondaryなので実態とズレている。
  • 大阪のクラスターに対してCDK上の変更が反映できるかを確認する(実装上は東京Primary、大阪Secondaryのまま、大阪のインスタンス数を変更する)。

ではやってみます。まずは東京Primary, 大阪Secondaryの状態から、計画内フェイルオーバーを実行します。

大阪がPrimaryになりました。

ではCDK上で大阪のインスタンスを2にして反映できるか試してみます。diffを取ると以下のような感じです。

これでcdk deployを行い、反映してみると....できました。大阪のインスタンスが2つになっています。特に問題なさそうです。

②計画外フェイルオーバー実施後、実態とCDKがずれた状態でCDK上の設定変更を反映できるか

一旦状態をリセットします(東京Primary, 大阪Secondary)。

ここでやりたいことは以下です。

  • マネコン上で計画外フェイルオーバーを行い、大阪のAuroraクラスターを単独に昇格させ、東京のAuroraクラスターとグローバルデータベースは削除する。この時CDK上では東京Primary、大阪Secondaryのグローバルデータベースなので実態とズレている。
  • 大阪のクラスターに対してCDK上の変更が反映できるかを確認する(実装上は東京Primary、大阪Secondaryのまま、大阪のインスタンス数を変更する)。

ではやっていきます。今回はマネコン上で大阪のAuroraクラスターを選択した状態で、「グローバルデータベースから削除」を行います。 こうすることで大阪のAuroraクラスターがグローバルデータベースから切り離され、昇格します。

「昇格中」を挟み、昇格状態となりました(昇格した後のスクショ撮り忘れた、、、)

ではCDK上で大阪のインスタンス数を2にしてみます。diffを取ると以下になります。

cdk deployを行うと、「作成中」となり....

作成できました。②も問題なさそうです。

③計画外フェイルオーバー実施後、手動で実態とCDKを一致させた状態でCDK上の設定変更を反映できるか

では最後のパターンです。

ここでやりたいことは②の事後状態(大阪のAuroraクラスター単独)から、手動で無理やりCDKの実装(東京Primary, 大阪Secondaryのグローバルデータベース)の状態にもどし、CDKの設定変更の反映(CDKによる運用継続)ができるかを検証します。

流れとしては以下です。

  • 大阪単独からグローバルデータベース(大阪Primary, 東京Secondary)にする。
  • 計画内フェイルオーバーを行い、東京Primary, 大阪Secondaryにする(ここで実態とCDK上の実装が一致する)。
  • CDKによる設定変更の反映を行い、運用継続できるかを検証。

ではやっていきます。まず大阪のAuroraクラスターを選択した状態で「リージョンを追加」を押下します。

そしてグローバルデータベースと、東京のAuroraクラスター(Secondary)を作成していきます。ここでの注意点として、識別子や各種設定はCDK上のものと一致するように設定してきます。

上記で作成すると大阪Primary、東京Secondaryのグローバルデータベースが作成されます。

この状態で計画内フェイルオーバーを行い、PrimaryとSecondaryを入れ替えます。東京Primary、大阪Secondaryのグローバルデータベースになりました。これでようやく実態とCDK上の実装が一致した状態になりました。

ではCDK上の設定変更が反映できるかを試してみます。ここでは東京のインスタンス数を1→2, 大阪のインスタンス数を2→1にする変更をかけてみます。diffを取ると以下のような感じです。

この状態でcdk deployを行ってみたところ反映できました。手動で無理やりCDKの実装と一致する状態に戻しましたが、問題なくこの後も運用継続できそうです。

まとめ

今回は以下が可能であることを検証してみました。

ただ場合によってはよからぬ動作をする可能性もあるので、ズレている状態で変更を多用するのはあまりよろしくないかと思います。

  • ①計画内フェイルオーバー実施後、実態とCDKがずれた状態でCDK上の設定変更を反映できるか
  • ②計画外フェイルオーバー実施後、実態とCDKがずれた状態でCDK上の設定変更を反映できるか
  • ③計画外フェイルオーバー実施後、手動で実態とCDKを一致させた状態でCDK上の設定変更を反映できるか

また③では手動設定の箇所があるので、ミスっても大丈夫か、ミスった場合のリカバリの手段はあるか等運用面での追加検討は必要かと思います。別途そちらはまた検証してみたいと思います。