1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS CDK】「CDKを用いた1APP2StackでのAurora Global Databaseの実装」

Last updated at Posted at 2024-04-03

はじめに

Auroraには、マルチリージョンレプリケーションを構成するGlobal Databaseの機能があります。
Amazon Aurora Global Database

目的としては、各リージョンにリードレプリカを置いて、リージョン毎のレイテンシーを低減させるためですが、DR(Disaster Recovery)観点でも活用される機能かと思われます。

この機能自体をCDKで実装する場合、いくつかポイントがあるので、そのポイントをご紹介させて頂きます。
本記事では、Stack間のパラメータ引き渡しがない、1APP2Stack構成でのご紹介となります。
※CDKを用いて実装する場合、Stackコードはリージョンに紐つくため、1Stackコードでは実装することは出来ません。ソースとなるプライマリDBクラスタ(Aurora Writerインスタンス)をDeployするリージョンに紐つくStack、セカンダリDBクラスタ(Aurora Readerインスタンス)をDeployするリージョンに紐つくStackの2つに分割する必要があります。

※ 本ブログに記載した内容は個人の見解であり、所属する会社、組織とは全く関係ありません。

1APP 2Stack構成でのAurora Global Databaseの実装

本サンプルでは、以下シナリオ構成でAurora Serverless V2のGlobal Databaseの実装します。

シナリオ
ソースとなるプライマリDBクラスタ(Aurora Writerインスタンス)を東京Regionに、セカンダリDBクラスタ(Aurora Readerインスタンス)を大阪RegionにDeployする。

このサンプルは以下6つのセクションに分割されます。

  • APPコード
  • パラメータファイル
  • ソースとなるプライマリDBクラスタ(Aurora Writerインスタンス)用Stackコード
  • ソースとなるプライマリDBクラスタ(Aurora Writerインスタンス)用Constructsコード
  • セカンダリDBクラスタ(Aurora Readerインスタンス)用Stackコード
  • セカンダリDBクラスタ(Aurora Readerインスタンス)用Constructsコード

ポイントとしては、プライマリDBクラスタ側でも、セカンダリDBクラスタ側でも同じ"globalClusterIdentifier"を指定する必要があります。
よって、簡略化、ミスの抑制を意識し、このパラメータを外に出し同じパラメータを参照させるようにしています。
※利用しているパラメータの外だし手法に関しては、以下のリンクの記事をご参照ください。
【AWS CDK】「CDKにおけるパラメータの外だし方法 ~自前TypeScript実装編~」

詳細は、それぞれのセクションに分けてご紹介させて頂きます。

APPコード

globalAuroraがプライマリDBクラスタを東京RegionにDeployします。
replicaAuroraがセカンダリDBクラスタを大阪RegionにDeployします。

sample-global-aurora.ts
// プライマリDBクラスタ
const globalAurora = new SampleGlobalAuroraStack(app, 'globalAurpra', {
    env: {
    region: "ap-northeast-1",
    account: "xxxx"
  },
tsEnv: envName,
});

// セカンダリDBクラスタ
const replicaAurora =  new SampleReplicaAuroraStack(app, 'replicaAurora', {
    env: {
    region: "ap-northeast-3",
    account: "xxxx"
  },
tsEnv: envName,
});

APPコードを構成するポイントはStack Constructsに引き渡すprops(引数のセット)です。

env
env propsにてDeployする先のRegionを指定することが出来ます。
そのため、globalAuroraではap-northeast-1(東京)を、replicaAuroraではap-northeast-3(大阪)を指定しています。

パラメータファイル

パラメータは以下のように組んでいます。
nwTokyoの部分はglobalAurora専用、nwOsakaの部分はreplicaAurora専用、globaldbの部分は両Stack共用といった構成にしています。
この共用箇所設けることにより、管理簡略化、ミスの抑制を狙っています。

Dev.ts
export const nwTokyo = {
  cidr: "10.0.0.0/24",
};
export const nwOsaka = {
  cidr: "10.0.1.0/24",
};

export const globaldb = {
  globalClusterId: "global-test",
};

ソースとなるプライマリDBクラスタ(Aurora Writerインスタンス)Stackコード

ソースとなる プライマリDBクラスタとAurora Writerインスタンスを構成するStackコードです。
特徴的な箇所は有りませんが、パラメータ外だしに関連する対応を実施しています。

sample-global-aurora-stack.ts
  constructor(scope: Construct, id: string, props: SampleGlobalAuroraStackProps) {
    super(scope, id, props);
    const config = require("../config/" + props.tsEnv);
    const globalAurora = new GlobalAurora(this, "globalaurora", {
      cidr: config.nwTokyo.cidr,
      globalClusterId: config.globaldb.globalClusterId
    })
  }

ソースとなるプライマリDBクラスタ(Aurora Writerインスタンス)用Constructsコード

ソースとなる プライマリDBクラスタとAurora Writer インスタンスを構成するConstructsコードです。

sample-global-aurora-constructs.ts
    //Aurora Cluster
    const myMainAuroraCluster = new rds.DatabaseCluster(this, "MainAuroraCluster", {
      engine: rds.DatabaseClusterEngine.auroraPostgres({ version: rds.AuroraPostgresEngineVersion.VER_14_4 }),
      clusterIdentifier: `mainauroracluster`,
      writer: rds.ClusterInstance.serverlessV2("writer", {
        autoMinorVersionUpgrade: false,
        enablePerformanceInsights: true,
        instanceIdentifier: `MainAuroraWriter`,
        performanceInsightRetention: 93,
        scaleWithWriter: true,
      }),
      serverlessV2MaxCapacity: 2,
      serverlessV2MinCapacity: 1,
      backup:{
        retention: cdk.Duration.days(30),
        preferredWindow: "18:00-19:00",
      },
      cloudwatchLogsExports: ["postgresql"],
      cloudwatchLogsRetention: logs.RetentionDays.THREE_MONTHS,
      deletionProtection: false, 
      preferredMaintenanceWindow: "Sat:17:00-sat:18:00",
      subnetGroup: myMainAuroraSubnetGp,
      storageEncrypted: false,
      vpc: myVpc,
    });
    
    // Aurora ClusterをGlobal Database化
    new rds.CfnGlobalCluster(scope, 'MainGlobalDatabase', {
      globalClusterIdentifier: props.globalClusterId,
      sourceDbClusterIdentifier: myMainAuroraCluster.clusterIdentifier
      })

注意点
本構成では、ストレージ暗号化せずに構成しております。
暗号化する場合は、以下propsを指定してください。

  • storageEncrypted
  • storageEncryptionKey

また、Global Databaseを利用する場合は、KMSマルチリージョンキーを用いる必要があります。
CDKを用いたマルチリージョンキーの実装に関しては以下をご確認ください。
KMSマルチリージョンキーの実装

ポイントは作成したAurora ClusterをGlobal Databaseにしているところです。

new rds.CfnGlobalCluster(scope, 'MainGlobalDatabase', {
L1 CfnGlobalCluster Constructsを用いてGlobal Database化しています。

globalClusterIdentifier: props.globalClusterId,
グローバルデータベースの識別子です。
パラメータファイルからglobalClusterIdを呼び込みglobalClusterIdentifierに入れ込んでいます。
この値がGlobal Databaseを組むときのKeyとなります。

sourceDbClusterIdentifier: myMainAuroraCluster.clusterIdentifier
作成したAurora Clusterを指定し、このGlobal Databaseのソースとしています。

セカンダリDBクラスタ(Aurora Readerインスタンス)用Stackコード

レプリケーション先のセカンダリDBクラスタとAurora Readerを構成するStackコードです。
特徴的な箇所は有りませんが、パラメータ外だしに関連する対応を実施しています。

sample-replica-aurora-stack.ts
  constructor(scope: Construct, id: string, props: SampleReplicaAuroraStackProps) {
    super(scope, id, props);
    const config = require("../config/" + props.tsEnv);
    new ReplicaAurora(this, "ReplicaAsurora", {
      cidr: config.nwOsaka.cidr,
      globalClusterId: config.globaldb.globalClusterId
    }
    )
  }

セカンダリDBクラスタ(Aurora Readerインスタンス)用Constructsコード

レプリケーション先のセカンダリDBクラスタとAurora Reader を構成するConstructsコードです。

sample-replica-aurora-constructs.ts
    //Aurora Cluster
    const myMainAuroraCluster = new rds.DatabaseCluster(this, "MainAuroraCluster", {
      engine: rds.DatabaseClusterEngine.auroraPostgres({ version: rds.AuroraPostgresEngineVersion.VER_14_4 }),
      clusterIdentifier: `mainauroracluster`,
      writer: rds.ClusterInstance.serverlessV2("writer", {
        autoMinorVersionUpgrade: false,
        enablePerformanceInsights: true,
        instanceIdentifier: `MainAuroraWriter`,
        performanceInsightRetention: 93,
        scaleWithWriter: true,
      }),
      serverlessV2MaxCapacity: 2,
      serverlessV2MinCapacity: 1,
      backup:{
        retention: cdk.Duration.days(30),
        preferredWindow: "18:00-19:00",
      },
      cloudwatchLogsExports: ["postgresql"],
      cloudwatchLogsRetention: logs.RetentionDays.THREE_MONTHS,
      deletionProtection: false, 
      preferredMaintenanceWindow: "Sat:17:00-sat:18:00",
      subnetGroup: myMainAuroraSubnetGp,
      storageEncrypted: false,
      vpc: myVpc,
    });
    
    
    //エスケープハッチ
    const cfnReplicaCluster = myMainAuroraCluster.node.defaultChild as rds.CfnDBCluster
    cfnReplicaCluster.masterUsername = undefined;
    cfnReplicaCluster.masterUserPassword = undefined;
    cfnReplicaCluster.globalClusterIdentifier = props.globalClusterId

注意点
Writerインスタンスから同期されるため、「defaultDatabaseName」は指定できません。

ポイントはAurora Serverless V2のインスタンスを指定しているところと、エスケープハッチをしているところの2箇所になります。

writer: rds.ClusterInstance.serverlessV2("writer", {
Readerインスタンスなのになぜwriterって感じですよね?
L2 DatabaseCluster Constructsの仕様により、Wtiterインスタンスを必ず配置する必要があります。Readerだけで書いてしまうとエラーが発生します。
しかし、実際GlobalDatabaseでDeployするとReaderインスタンスとしてdeployされるので、問題はありません。
仕様上仕方ありませんが、紛らわしいですね。

エスケープハッチ
L2 DatabaseCluster Constructsでは、GlobalDatabaseに関わる設定をすることが出来ません。
そのため、エスケープハッチで設定を当て込んでいます。
CDK Constructs

エスケープハッチの詳しい検討方法等は以下の記事をご参照ください。
エスケープハッチサンプル

まずは、「tree.json」を確認します。

tree.json
                  "Resource": {
                    "id": "Resource",
                    "path": "replicaAurora/ReplicaAsurora/MainAuroraCluster/Resource",
                    "attributes": {
                      "aws:cdk:cloudformation:type": "AWS::RDS::DBCluster",

replicaAuroraのMainAuroraClusterのPathがResourceになっており、CloudFormation:typeもRDS::DBClusterになっています。
よって、myMainAuroraClusterのdefaultchildはCfnDBClusterにキャスト出来ることがわかります。

const cfnReplicaCluster = myMainAuroraCluster.node.defaultChild as rds.CfnDBCluster
エスケープハッチし、CfnDBClusterにキャストし、cfnReplicaCluster に入れています。

cfnReplicaCluster.masterUsername = undefined;
cfnReplicaCluster.masterUserPassword = undefined;
Read Replicaインスタンスなので、認証情報はWriterと同期します。そのため、undefinedを指定します。

cfnReplicaCluster.globalClusterIdentifier = props.globalClusterId
グローバルデータベースの識別子です。
パラメータファイルからglobalClusterIdを呼び込みglobalClusterIdentifierを指定します。
Writerインスタンス側のDBクラスタと同じパラメータを指定しているので、Global DatabaseのReaderとして構成されます。

Deploy結果

RDSの画面では以下のようになり、無事Global Databaseとして構成されていることがわかります。
image.png

まとめ

今回は、CDKを用いたAurora Global Databaseの構成方法をご紹介させて頂きました。
特段難しい箇所があるということではないんですが、ちょこちょこ素直に使えないポイントがあったり、パラメータ外だしに向いていたり、特徴があります。
このようにDeployするリソースにKeyとして同じパラメータを指定しなければいけないケースなんかには、パラメータ外だし構成は向いていますね。
Aurora Global Databaseのご利用をご検討の際は、ご紹介させて頂いた内容を参考にして頂けると幸いです。
※ 本ブログに記載した内容は個人の見解であり、所属する会社、組織とは全く関係ありません。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?