東京・大阪でAmazon Aurora Global Databaseを組み、大阪はヘッドレスクラスターにする構成を、AWS CloudFormationで構築してみた

東京・大阪でAmazon Aurora Global Databaseを組み、大阪はヘッドレスクラスターにする構成を、AWS CloudFormationで構築してみた

東京と大阪にまたがるAmazon Aurora Global Databaseにて、大阪リージョンではストレージのみのヘッドレスクラスターとする構成を考えます。この構成を、AWS CloudFormationテンプレートで記述してデプロイします。
Clock Icon2025.07.06

Amazon AuroraのGlobal Database(東京・大阪)で、大阪だけヘッドレスにしたい

おのやんです。

みなさんAmazon Aurora(以下、Aurora)のストレージはマルチリージョンでバックアップを取り、かつコストを抑えた構成にしたいと思ったことはありますか?私はあります。

AuroraにはGlobal Databaseという構成をとることができ、例えば東京・大阪といったマルチリージョン間でデータを同期させることができます。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/aurora-global-database.html

また、Auroraには別途ヘッドレスクラスターという構成もとることができます。Auroraではコンピューティングとストレージが分離しており、ストレージを残してコンピューティング部分だけ削除して、コンピューティング部分の課金を抑えるような構成が可能です。

https://dev.classmethod.jp/articles/aurora-headless-db-cluster/

以上を組み合わせて、「東京・大阪にまたがるAurora Global Database構成を取ってマルチリージョンにデータを同期し、大阪だけヘッドレス構成にして大阪はインスタンス課金が発生しない(ストレージ課金のみ)」ような構成を組むことができます。

architecture

ヘッドレスクラスターは、通常のAWSマネジメントコンソール上からは作成できないので、AWS CLIやAWS SDK(Boto3など)、IaCなどを使って構築する必要があります。

現在、RDS コンソールでは、ヘッドレスクラスターの作成はサポートされていません。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/aurora-global-database-attach.console.headless.html

この構成を実現するために、AWS CloudFormation(以下、CFn)テンプレートをどう記述する必要があるのか検証しましたので、その内容を今回は紹介します。

CFnテンプレート

今回使用したCFnテンプレートはこんな感じで、東京と大阪で2つのCFnテンプレートを使います。東京の方で記述しているAWS::RDS::DBInstanceのリソースを、大阪の方では記述しないことで、大阪リージョンのクラスターがストレージのみとなります。

東京リージョンデプロイ分テンプレート
aurora-global-headless-tokyo.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: Aurora PostgreSQL Global Database Primary Cluster in Tokyo Region

Parameters:
  SystemName:
    Type: String
    Default: aws

  EnvName:
    Type: String
    Default: test

Resources:
  #============================================================#
  # VPC
  #============================================================#

  AWSTestVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: Aurora-Global-VPC-Tokyo

  #============================================================#
  # Private subnets
  #============================================================#

  AWSTestPrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref AWSTestVPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      Tags:
        - Key: Name
          Value: Aurora-Private-Subnet-1

  AWSTestPrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref AWSTestVPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: !Select [1, !GetAZs '']
      Tags:
        - Key: Name
          Value: Aurora-Private-Subnet-2

  #============================================================#
  # DB Subnet Group
  #============================================================#

  AWSTestDBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: Subnet group for Aurora Global Database
      SubnetIds:
        - !Ref AWSTestPrivateSubnet1
        - !Ref AWSTestPrivateSubnet2
      Tags:
        - Key: Name
          Value: Aurora-Global-SubnetGroup

  #============================================================#
  # Security Group for Aurora
  #============================================================#

  AWSTestAuroraSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for Aurora PostgreSQL
      VpcId: !Ref AWSTestVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 5432
          ToPort: 5432
          CidrIp: 10.0.0.0/16
      Tags:
        - Key: Name
          Value: Aurora-Global-SecurityGroup

  #============================================================#
  # Aurora Global Database
  #============================================================#

  # Aurora Global Database
  AWSTestAuroraGlobalDatabase:
    Type: AWS::RDS::GlobalCluster
    Properties:
      GlobalClusterIdentifier: !Sub ${SystemName}-${EnvName}-aurora-global-cluster
      Engine: aurora-postgresql
      EngineVersion: 15.4
      StorageEncrypted: true

  #============================================================#
  # Primary Aurora DB Cluster
  #============================================================#

  # Primary Aurora DB Cluster
  AWSTestAuroraDBCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DBClusterIdentifier: !Sub ${SystemName}-${EnvName}-aurora-db-cluster-primary
      Engine: aurora-postgresql
      EngineVersion: 15.4
      MasterUsername: postgres
      MasterUserPassword: password # 本番環境ではAWS Secrets Managerなどで強力なパスワードを必ず管理してください
      DBSubnetGroupName: !Ref AWSTestDBSubnetGroup
      VpcSecurityGroupIds:
        - !Ref AWSTestAuroraSecurityGroup
      StorageEncrypted: true
      BackupRetentionPeriod: 7
      PreferredBackupWindow: 03:00-04:00
      PreferredMaintenanceWindow: sun:04:00-sun:05:00
      GlobalClusterIdentifier: !Ref AWSTestAuroraGlobalDatabase

  #============================================================#
  # Primary Aurora DB Instance
  #============================================================#

  # Primary Aurora DB Instance
  AWSTestAuroraDBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: !Sub ${SystemName}-${EnvName}-aurora-db-instance-primary
      DBInstanceClass: db.r5.large
      Engine: aurora-postgresql
      DBClusterIdentifier: !Ref AWSTestAuroraDBCluster
      PubliclyAccessible: false

Outputs:
  GlobalClusterIdentifier:
    Description: Aurora Global Database Identifier
    Value: !Ref AWSTestAuroraGlobalDatabase
    Export:
      Name: !Sub ${AWS::StackName}-GlobalClusterIdentifier
大阪リージョンデプロイ分テンプレート
aurora-global-headless-osaka.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: Aurora PostgreSQL Global Database Headless Secondary Cluster in Osaka Region

Parameters:
  SystemName:
    Type: String
    Default: aws
    Description: System name of each resource names

  EnvName:
    Type: String
    Default: test
    Description: Environment name of each resource names

  GlobalClusterIdentifier:
    Type: String
    Description: Global cluster identifier from primary region

Resources:
  #============================================================#
  # VPC
  #============================================================#

  AWSTestVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.1.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: Aurora-Global-VPC-Osaka

  #============================================================#
  # Private subnets
  #============================================================#

  AWSTestPrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref AWSTestVPC
      CidrBlock: 10.1.1.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      Tags:
        - Key: Name
          Value: Aurora-Private-Subnet-1

  AWSTestPrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref AWSTestVPC
      CidrBlock: 10.1.2.0/24
      AvailabilityZone: !Select [1, !GetAZs '']
      Tags:
        - Key: Name
          Value: Aurora-Private-Subnet-2

  #============================================================#
  # DB Subnet Group
  #============================================================#

  AWSTestDBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: Subnet group for Aurora Global Database Secondary
      SubnetIds:
        - !Ref AWSTestPrivateSubnet1
        - !Ref AWSTestPrivateSubnet2
      Tags:
        - Key: Name
          Value: Aurora-Global-SubnetGroup-Secondary

  #============================================================#
  # Security Group for Aurora
  #============================================================#

  AWSTestAuroraSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for Aurora PostgreSQL Secondary
      VpcId: !Ref AWSTestVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 5432
          ToPort: 5432
          CidrIp: 10.1.0.0/16
      Tags:
        - Key: Name
          Value: Aurora-Global-SecurityGroup-Secondary

  #============================================================#
  # Secondary Aurora DB Cluster (Headless - no instances)
  #============================================================#

  AWSTestAuroraDBCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DBClusterIdentifier: !Sub ${SystemName}-${EnvName}-aurora-db-cluster-secondary
      Engine: aurora-postgresql
      EngineVersion: 15.4
      DBSubnetGroupName: !Ref AWSTestDBSubnetGroup
      VpcSecurityGroupIds:
        - !Ref AWSTestAuroraSecurityGroup
      StorageEncrypted: true
      KmsKeyId: alias/aws/rds
      GlobalClusterIdentifier: !Ref GlobalClusterIdentifier

東京では、このようにAuroraクラスターに加えてAuroraインスタンスも記述しています。

  #============================================================#
  # Primary Aurora DB Cluster
  #============================================================#

  # Primary Aurora DB Cluster
  AWSTestAuroraDBCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DBClusterIdentifier: !Sub ${SystemName}-${EnvName}-aurora-db-cluster-primary
      Engine: aurora-postgresql
      EngineVersion: 15.4
      MasterUsername: postgres
      MasterUserPassword: password # 本番環境ではAWS Secrets Managerなどで強力なパスワードを必ず管理してください
      DBSubnetGroupName: !Ref AWSTestDBSubnetGroup
      VpcSecurityGroupIds:
        - !Ref AWSTestAuroraSecurityGroup
      StorageEncrypted: true
      BackupRetentionPeriod: 7
      PreferredBackupWindow: 03:00-04:00
      PreferredMaintenanceWindow: sun:04:00-sun:05:00
      GlobalClusterIdentifier: !Ref AWSTestAuroraGlobalDatabase

  #============================================================#
  # Primary Aurora DB Instance
  #============================================================#

  # Primary Aurora DB Instance
  AWSTestAuroraDBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: !Sub ${SystemName}-${EnvName}-aurora-db-instance-primary
      DBInstanceClass: db.r5.large
      Engine: aurora-postgresql
      DBClusterIdentifier: !Ref AWSTestAuroraDBCluster
      PubliclyAccessible: false

一方で大阪では、Auroraクラスターのみを記述することで、大阪リージョンではヘッドレスクラスターになります。

  #============================================================#
  # Secondary Aurora DB Cluster (Headless - no instances)
  #============================================================#

  AWSTestAuroraDBCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DBClusterIdentifier: !Sub ${SystemName}-${EnvName}-aurora-db-cluster-secondary
      Engine: aurora-postgresql
      EngineVersion: 15.4
      DBSubnetGroupName: !Ref AWSTestDBSubnetGroup
      VpcSecurityGroupIds:
        - !Ref AWSTestAuroraSecurityGroup
      StorageEncrypted: true
      KmsKeyId: alias/aws/rds
      GlobalClusterIdentifier: !Ref GlobalClusterIdentifier

構築

実際の構築手順は次のようになります。

  • 東京用テンプレートを使って、東京リージョンにAurora Global Databaseを構築
  • Aurora Global DatabaseのクラスターIDをメモ
  • 大阪用テンプレートを使って、大阪リージョンにAurora Global Databaseを構築
    • この際、メモしたクラスターIDをパラメータとして入力

まずは、東京用テンプレートを使って、東京リージョンにAurora Global Databaseを構築します。

% aws cloudformation create-stack \
  --stack-name aurora-global-primary-tokyo \
  --template-body file://aurora-global-headless-tokyo.yaml \
  --region ap-northeast-1

{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:************:stack/aurora-global-primary-tokyo/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

構築には数分かかりますが、構築が完了すると、このようにAuroraクラスターの上位にGlobal Databaseが設定されていることが分かります。

スクリーンショット 2025-07-06 15.45.06

このGlobal DatabaseのIDをメモします。

スクリーンショット 2025-07-06 16.03.10

このIDをパラメータとして入力して、同様に大阪リージョンでも作成していきます。

% aws cloudformation create-stack \
   --stack-name aurora-global-secondary-osaka \
   --template-body file://aurora-global-headless-osaka.yaml \
   --parameters ParameterKey=GlobalClusterIdentifier,ParameterValue=<取得したGlobal Database ID> \
   --region ap-northeast-3

{
    "StackId": "arn:aws:cloudformation:ap-northeast-3:************:stack/aurora-global-secondary-osaka/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

作成が完了すると、このように大阪リージョンでGlobal Databaseの確認ができるようになります。

スクリーンショット 2025-07-06 16.49.42

クロスリージョンですので、東京リージョンでも同様にコンソールに表示されます。

スクリーンショット 2025-07-06 16.49.53

既存のGlobal Databaseを指定した状態で、セカンダリリージョンではインスタンスを作成しないことでヘッドレスクラスターとする

CFnテンプレートに関しては、東京リージョンと大阪リージョンで別々のCFnテンプレートを用意し、先にデプロイした東京のGlobal Databaseを大阪デプロイ時に指定する必要があると分かりました。

また、大阪側をヘッドレスクラスターにする場合は、Auroraインスタンスを記載しないことが必要です。

構築するにあたって気になる部分でしたので、ひとまず検証できました。この記事が参考にされば幸いです。では!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.