検証目的のためにCloudFormationでシングルインスタンスのAuroraを建てようとしたら手こずった話

# 本記事の内容

- AWSが提供するCloudFormationサービスを利用し、データベース(RDS)の一つであるAuroraをシングルインスタンスで建てる方法を記載した記事です。
- 検証目的のため等、インスタンスを冗長化せずシングル構成で作成したいこともあるかと思います。たくさん建てますとお金もかかりますし。ネットにはシングルインスタンス構成で構築した情報があまりなく、冗長構成前提の情報が多かったため、試行錯誤して完成したCloudFormationテンプレートを本記事にまとめました。参考情報になれば幸いです。


本記事の手順で以下のような構成のクラウド環境を作成します。
![CF_Aurora-ページ1.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/0c221a43-0f07-ed08-5722-68c630bc542f.png)
※AWSの操作画面はサービスリリースと共に更新されていくため、本記事をご覧いただくタイミングによっては、現在の画面と異なる場合があります。ご了承ください。本記事内の画面キャプチャーは2022年9月時点,

まずAuroraをシングルインスタンス構成で建てる時の試行錯誤で気づいたことを以下に記載しておきます。

- 気づき
	- 1.CloudFormationテンプレートにDBインスタンスの設定(Type: AWS::RDS::DBInstance)だけでなく、クラスター設定(Type: AWS::RDS::DBCluster)も必要である
	- 2.シングルインスタンスとはいえど、Auroraの仕様でVPC内にアベイラビリティーゾーン(AZ)は最低二つ必要となり、それらをDBサブネットグループとして定義する必要がある


これらは有識者にとっては当たり前かもしれませんが、
私は知らなかったので、CloudFormationテンプレートを作成する中で躓きました。
AWS公式ドキュメントを読むとこのあたりが必要な理由が分かったので、以下に私の理解を書きます。

- なぜこのような設定が必要なのか？
	-  1は、[Auroraの仕様](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/Aurora.Overview.html)を読むことで私の理解が足りていなかったのだと分かりました。Aurora自体が「DBインスタンス層」とデータを管理する「クラスターボリューム層」からなる構成されていて、これらをまとめた物がAurora DB Clusterとして定義されています。そのためインスタンスの設定(Type: AWS::RDS::DBInstance)だけでなく、クラスター(Type: AWS::RDS::DBCluster)の設定も必要なのだと理解しました。クラスターボリューム層の定義は不要なのか？という点が気になりましたが、ここはCluster設定に内包されており、本サービスがマネージドサービスであるため良い感じに管理してくれていると割り切って解釈しました。間違っていたら申し訳ないです。
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/bffbbce2-7dab-b6e0-46bf-880d3faf441a.png)

	-  2は、AWSの[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/Aurora.CreateInstance.html)の赤で囲った仕様に基づくもので、DBクラスターにはサブネットグループが必要であり、サブネットグループには少なくとも二つのAZに紐づくようにサブネットを定義しておく必要があると記載がありました。
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/8a78d814-f5c0-d61b-518d-5f18bb56256c.png)


ここから実際のテンプレートを説明していきます。

# 実施環境
- Windows 10
- Chrome
- AWS

# 説明の流れ
1. CloudFormationスタックの作成
2. CloudFormationテンプレートの説明


## 1. CloudFormationスタックの作成

AWSマネジメントコンソールにアクセスし、「CloudFormationサービス」を選択する。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/c33a5671-d929-52f4-5a71-7e0bd2cc8e96.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/3fa839ba-6ae3-1f13-4a7a-b6085cd5100c.png)

「スタックの作成」をクリックする。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/8305d97f-46b5-7fb7-4fa2-037a363499b0.png)

「テンプレートファイルのアップロード」をクリックする。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/4c89ea04-3720-eba6-68e2-fbfab90d5cd7.png)

「ファイルの選択」をクリックし、アップロードするテンプレートファイルを選択する。※ファイルは、2.CloudFormationテンプレートの説明に記載の「aurora_template_for_Qita_Single_Instance.txt」
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/449b1d01-2195-05a3-e4c3-ebf68bc8d6dc.png)

「次へ」をクリックする。
![cf_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/e65c56e1-8448-8992-bd65-3310706c3304.png)

スタックの名前とパラメータは任意の値を設定すること。
![cf_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/b28b6389-c6e7-d029-219c-e37584c89f6a.png)

「次へ」をクリックする。
![cf_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/faf89b4a-0ba6-1d93-1340-b8de99bba874.png)

デフォルトのまま下へスクロールし、「次へ」をクリックする。
![cf_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/f32a7af5-b9f5-bc4b-8f6a-b4db058f07b4.png)
![cf_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/c3fd9aa5-5ba1-6848-3df7-c8f32c2211c5.png)


デフォルトのまま下へスクロールし、「スタックの作成」をクリックする。
![cf_09_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/6c2428c0-903b-f020-91ac-360fbe04861b.png)
![cf_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/a34a5025-a6cd-3278-7724-1a55c0d7188a.png)

CloudFormationによるサービスの作成が始まった。「CREATE_IN_PROGRESS」が「CREATE_COMPLETE」に代わるまで待つ。
![cf_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/367a8517-51ec-d201-84f5-de0f99ac834a.png)
![cf_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/d6ddf5cd-3bdf-412e-03c3-64dc65dfcb66.png)
![cf_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/44af0fcc-f51a-30e7-933e-4f8b975cdc82.png)

CloudFormationが完了したらRDSのサービスを開き、Auroraがシングルインスタンスで構築されていることを確認できた。
![cf_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/4d4a6ef3-a4c7-76d8-90e1-e16b7c4a6e5c.png)


## 2. CloudFormationテンプレートの説明

以下が実際に投入したファイルです。

```yaml:aurora_template_for_Qita_Single_Instance.txt
AWSTemplateFormatVersion: 2010-09-09
#####################################################
# Parameters
#####################################################
Parameters:
  DBMasterUserName:
    Description: Please enter the name of the master user on an RDS.
    Type: String
    Default: master

  DBMasterUserPassword:
    Description: Please enter the RDS password.
    Type: String
    Default: s8Ekv42Iq
    NoEcho: true

  VpcSubnet:
    Description: VPC subnet
    Type: String
    Default: 10.0.0.0/16

#####################################################
# Mappings
#####################################################
Mappings:
  Constant:
    RDS:
      ClusterName: test-aurora-cluster
      DatabaseName: auroradb
      InstanceName: test-aurora-instance1
      InstanceType: db.t3.small

#####################################################
# Resource
#####################################################

#####################################################
#  VPC section
#####################################################

Description: Create VPC
Resources:
  TestVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcSubnet
      Tags:
        - Key: Name
          Value: TestVPC

#####################################################
#  Subnet section
#####################################################

  TestPrivateSub1a:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Select [0, !Cidr [!GetAtt TestVPC.CidrBlock, 2, 8]] #10.0.0.0/24
      MapPublicIpOnLaunch: false
      VpcId: !Ref TestVPC
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: TestPrivateSub1a

  TestPrivateSub1c:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Select [1, !Cidr [!GetAtt TestVPC.CidrBlock, 2, 8]] #10.0.1.0/24
      MapPublicIpOnLaunch: false
      VpcId: !Ref TestVPC
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: TestPrivateSub1c

#####################################################
#  SecurityGroup section
#####################################################

  TestSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref "TestVPC"
      GroupDescription: Allow RDS Connection From TCP 3306 Port
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          CidrIp: !GetAtt "TestVPC.CidrBlock"
      Tags:
        - Key: Name
          Value: TestSecurityGroup

#####################################################
#  DBSubnetGroup section
#####################################################

  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: RDS subnet group.
      SubnetIds:
        - !Ref "TestPrivateSub1a"
        - !Ref "TestPrivateSub1c"

#####################################################
#  Aurora section
#####################################################


  # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-dbparametergroup.html
  DBParameterGroup:
    Type: "AWS::RDS::DBParameterGroup"
    Properties:
      Description: "RDS DB parameter group"
      Family: "aurora-mysql5.7"
      Parameters:
        max_connections: "10"
      Tags: 
        - Key: Name
          Value: TestClusterParamaterGroup

  # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-rds-dbclusterparametergroup.html
  DBClusterParameterGroup:
    Type: "AWS::RDS::DBClusterParameterGroup"
    Properties:
      Description: "RDS DB cluster parameter group"
      Family: "aurora-mysql5.7"
      Parameters:
        character_set_client: "utf8mb4"
        character_set_connection: "utf8mb4"
        character_set_database: "utf8mb4"
        character_set_filesystem: "utf8mb4"
        character_set_results: "utf8mb4"
        character_set_server: "utf8mb4"
        collation_connection: "utf8mb4_bin"
        collation_server: "utf8mb4_bin"
        time_zone: "UTC"
      Tags: 
        - Key: Name
          Value: TestClusterParamaterGroup

  DBCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      Engine: aurora-mysql
      EngineVersion: 5.7.mysql_aurora.2.10.2
      DatabaseName: !FindInMap [Constant, RDS, DatabaseName]
      DBClusterIdentifier: !FindInMap [Constant, RDS, ClusterName]
      MasterUsername: !Ref "DBMasterUserName"
      MasterUserPassword: !Ref "DBMasterUserPassword"
      DBSubnetGroupName: !Ref "DBSubnetGroup"
      DBClusterParameterGroupName: !Ref "DBClusterParameterGroup"
      VpcSecurityGroupIds:
        - !Ref "TestSecurityGroup"

  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      Engine: aurora-mysql
      EngineVersion: 5.7.mysql_aurora.2.10.2
      DBInstanceClass: !FindInMap [Constant, RDS, InstanceType]
      DBSubnetGroupName: !Ref "DBSubnetGroup"
      DBParameterGroupName: !Ref "DBParameterGroup"
      DBClusterIdentifier: !Ref "DBCluster"
      AvailabilityZone: ap-northeast-1a

```

以下が説明です。


```yaml
AWSTemplateFormatVersion: 2010-09-09
#####################################################
# Parameters
#####################################################
Parameters:
  DBMasterUserName:
    Description: Please enter the name of the master user on an RDS.
    Type: String
    Default: master

  DBMasterUserPassword:
    Description: Please enter the RDS password.
    Type: String
    Default: s8Ekv42Iq
    NoEcho: true

  VpcSubnet:
    Description: VPC subnet
    Type: String
    Default: 10.0.0.0/16
```
- AWSTemplateFormatVersion: 2010-09-09
    - 上記はテンプレートフォーマットのバージョン宣言で、年月日は固定です。CloudFormationテンプレートの先頭に記載するおまじない。

- Parametersセクションはユーザからの入力を変数として、テンプレートの中で利用する物です。
    - それぞれDBのユーザ名「DBMasterUserName」、DBのパスワード「DBMasterUserPassword」、VPCを配置するサブネット「VpcSubnet」であり、テンプレート内で参照しています。

```yaml
#####################################################
# Mappings
#####################################################
Mappings:
  Constant:
    RDS:
      ClusterName: test-aurora-cluster
      DatabaseName: auroradb
      InstanceName: test-aurora-instance1
      InstanceType: db.t3.small
```
- Mappings:
	- ここでMap型の固定値変数を設定しています。

```yaml
#####################################################
# Resource
#####################################################

#####################################################
#  VPC section
#####################################################

Description: Create VPC
Resources:
  TestVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcSubnet
      Tags:
        - Key: Name
          Value: TestVPC
```
- ここでAuroraを配置するためのVPCを作成します。「VpcSubnet」変数でユーザから入力された値を元にVPCのCidrを設定しています。


```yaml
#####################################################
#  Subnet section
#####################################################

  TestPrivateSub1a:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Select [0, !Cidr [!GetAtt TestVPC.CidrBlock, 2, 8]] #10.0.0.0/24
      MapPublicIpOnLaunch: false
      VpcId: !Ref TestVPC
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: TestPrivateSub1a

  TestPrivateSub1c:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Select [1, !Cidr [!GetAtt TestVPC.CidrBlock, 2, 8]] #10.0.1.0/24
      MapPublicIpOnLaunch: false
      VpcId: !Ref TestVPC
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: TestPrivateSub1c
```
- ここの記載で、VPC内に配置する二つのプライベートサブネットを定義しています。

```yaml
#####################################################
#  SecurityGroup section
#####################################################

  TestSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref "TestVPC"
      GroupDescription: Allow RDS Connection From TCP 3306 Port
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          CidrIp: !GetAtt "TestVPC.CidrBlock"
      Tags:
        - Key: Name
          Value: TestSecurityGroup
```
- Auroraに設定するセキュリティーグループを定義しています。送信元と、ポートにより通信路を制限しています。

```yaml
#####################################################
#  DBSubnetGroup section
#####################################################

  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: RDS subnet group.
      SubnetIds:
        - !Ref "TestPrivateSub1a"
        - !Ref "TestPrivateSub1c"
```
- Auroraを設定する際に必要なDBサブネットグループの定義です。VPC内に作成した二つのプライベートサブネットから構成されています。

```yaml
#####################################################
#  Aurora section
#####################################################


  # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-dbparametergroup.html
  DBParameterGroup:
    Type: "AWS::RDS::DBParameterGroup"
    Properties:
      Description: "RDS DB parameter group"
      Family: "aurora-mysql5.7"
      Parameters:
        max_connections: "10"
      Tags: 
        - Key: Name
          Value: TestClusterParamaterGroup

  # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-rds-dbclusterparametergroup.html
  DBClusterParameterGroup:
    Type: "AWS::RDS::DBClusterParameterGroup"
    Properties:
      Description: "RDS DB cluster parameter group"
      Family: "aurora-mysql5.7"
      Parameters:
        character_set_client: "utf8mb4"
        character_set_connection: "utf8mb4"
        character_set_database: "utf8mb4"
        character_set_filesystem: "utf8mb4"
        character_set_results: "utf8mb4"
        character_set_server: "utf8mb4"
        collation_connection: "utf8mb4_bin"
        collation_server: "utf8mb4_bin"
        time_zone: "UTC"
      Tags: 
        - Key: Name
          Value: TestClusterParamaterGroup

  DBCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      Engine: aurora-mysql
      EngineVersion: 5.7.mysql_aurora.2.10.2
      DatabaseName: !FindInMap [Constant, RDS, DatabaseName]
      DBClusterIdentifier: !FindInMap [Constant, RDS, ClusterName]
      MasterUsername: !Ref "DBMasterUserName"
      MasterUserPassword: !Ref "DBMasterUserPassword"
      DBSubnetGroupName: !Ref "DBSubnetGroup"
      DBClusterParameterGroupName: !Ref "DBClusterParameterGroup"
      VpcSecurityGroupIds:
        - !Ref "TestSecurityGroup"

  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      Engine: aurora-mysql
      EngineVersion: 5.7.mysql_aurora.2.10.2
      DBInstanceClass: !FindInMap [Constant, RDS, InstanceType]
      DBSubnetGroupName: !Ref "DBSubnetGroup"
      DBParameterGroupName: !Ref "DBParameterGroup"
      DBClusterIdentifier: !Ref "DBCluster"
      AvailabilityZone: ap-northeast-1a
```
- Auroraの定義です。
    - パラメータの設定として「DBParameterGroup」と「DBClusterParameterGroup」があります。
    - DBインスタンス本体とクラスターの設定として「DBInstance」と「DBCluster」があります。

本記事は以上です。
クラウド環境の作成の手助けになれば嬉しいです。

# 参考文献
本記事の作成に当たり、以下の情報も参考にさせて頂きました。ありがとうございました。
- [【AWS】実例で学ぶCloudFormation～RDS Aurora編～](https://qiita.com/tmiki/items/19cc4fc71949eaafbc3a)
- [CloudFormation の Fn::Cidr 組み込み関数の使い方のメモ。](https://ebc-2in2crc.hatenablog.jp/entry/2020/03/21/201028)
- [【AWS初学者向け・図解】CloudFormationの組み込み関数を現役エンジニアがわかりやすく解説②](https://o2mamiblog.com/aws-cloudformation-intrinsic-function-beginner-2/#toc2)