CloudFormationを使ってAuroraMySQLクラスターに結構無理やりな方法でカスタムエンドポイントを作った話
今回のテーマについて
こんにちわ!
DevelopersIO BASECAMP参加者の加藤です!
AuroraClusterには2023年3月現在
・ライター(クラスター)エンドポイント
・リーダーエンドポイント
・インスタンスエンドポイント
・カスタムエンドポイント
4種類のエンドポイントが存在します!
その中でも今回は「カスタムエンドポイント」の作成がテーマです。
早速ですが、まずはカスタムエンドポイントについての概要や勘所をまとめてみました!
早速カスタムエンドポイントの要点
Auroraクラスターには、
- ライター
- リーダー
- インスタンス
- カスタム
の4つのエンドポイントタイプがある。(2023年3月現在)
-
カスタムエンドポイントは他のワークロードとの負荷の分離をするのにとても有用。
-
カスタムエンドポイントには更に「WRITER」・「READER」・「ANY」の3タイプが存在する。
-
「WRITER」はマルチマスタークラスターでのみ選択可能。
-
ライターであるインスタンスもエンドポイントメンバーとして含めたい場合、WRITER/READERという意味の「ANY」を選択する必要がある。
・逆にライターインスタンスに影響を与える可能性を排除したい場合は「READER」を選択する必要がある。 -
マネコン(AWS Management Console)でやると簡単、CloudFormationでやるにはCustomResourceとLambda関数を使うなど工夫が必要。
-
一方でマネコンで作成されるカスタムエンドポイントは全てANYになる(2023年3月現在)
-
カスタムエンドポイントは本来はAWS CLIやRDS APIからの操作が推奨されている。
※カスタムエンドポイントを説明した記事の中でも特にわかりやすいのがこちら
そしてこちらがしっかりと概要を説明した本家のドキュメントになります。
大枠の理解が出来た所で早速挑戦していきたいと思います。
カスタムエンドポイントの作成
まずマネコン(AWS Management Console)でやってみた。
クラスターの作成が完成し、更に立ち上がったインスタンスにライター・リーダーの役割が与えられます。
↓
クラスターのDB識別子をクリックします。
↓
既に
・ライターエンドポイント
・リーダーエンドポイント
が作成されています。
先ほどのインスタンスはそれぞれの役割と一致するエンドポイントのメンバーとなっています。
[接続とセキュリティ]タブが開かれている事を確認し、
「カスタムエンドポイントの作成」をクリックします。
↓
①エンドポイント名を入力
②作成したカスタムエンドポイントに追加したいインスタンスを選択
③必要な場合は「今後作成されるインスタンスをこのクラスターにアタッチする」にチェックを入れます。(主に負荷増をきっかけにオートスケーリングされたリードレプリカなどが想定されます。)
「④エンドポイントの作成」をクリックします。
↓
カスタムエンドポイントが完成しました。
↓
中を覗くと、先ほどチェックをつけたインスタンスがメンバーになっている事が確認出来ます。
非常に直感的です。
CloudFormationでやってみた。
私が今回カスタムエンドポイントと組み合わせて実現させたかった事が以下になります。
①初期にライター・リーダーとなるインスタンスは意図的に選択したい。
②リーダーインスタンスは負荷でスケールさせたい。
③ライターとリーダーのインスタンスとカスタムエンドポイントのメンバーになるインスタンスのインスタンスクラスは別で指定したい。
④カスタムエンドポイントのメンバーになるインスタンスは単一障害点を避ける意味で、初期に作成台数を選択可能にしたい(一旦二台)。
⑤カスタムエンドポイントメンバーのインスタンスは出来る限り昇格して欲しくない。
とこのような内容の為、最小構成を紹介したテンプレートではない点はお許しください。
CloudFormtationでと決めて走り出したので、目的と手段の混同が見受けられる事や、
Lambda内に登記述しているPythonについてまだ見様見真似のレベルである為、アンチパターン的な要素が含まれる可能性がありますが、ご容赦の上生暖かい目で見ていただければ幸いです。
ざっくりとしたイメージ図。
サンプルテンプレート
長いので畳んであります。
SampleTemplate.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Challenge to create custom endpoints.
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
-
Label:
default: Tags and ResourceName
Parameters:
- PJPrefix
-
Label:
default: VPC and PrivateSubnets
Parameters:
- VPCCidrBlock
- PrivateSubnet1aCidrBlock
- PrivateSubnet1cCidrBlock
-
Label:
default: RDS (Aurora)
Parameters:
- EngineType
- MySQLMajorVersion
- MySQLMinorVersion
- AllowMajorVersionUpgrade
- AutoMinorVersionUpgrade
- PreferredMaintenanceWindow
- MinCapacityForApplicationAutoscaling
- MaxCapacityForApplicationAutoscaling
- TargetValueForApplicationAutoscaling
- ScaleInCooldownForApplicationAutoscaling
- ScaleOutCooldownForApplicationAutoscaling
- WriterAndReaderDBInstanceClass
- CustomEPMemberDBInstanceClass
- NumOfCustomEPMemberDBinstances
- CustomEndpointName
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
Parameters:
# for Tags and ResourceName
PJPrefix:
Type: String
# for VPC and PrivateSubnets
VPCCidrBlock: # VPCのCIDR範囲。
Type: String
Default: 10.1.0.0/16
MinLength: 9
MaxLength: 18
AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
PrivateSubnet1aCidrBlock: # プライベートサブネット1のCIDR範囲。
Type: String
Default: 10.1.0.0/24
MinLength: 9
MaxLength: 18
AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
PrivateSubnet1cCidrBlock: # プライベートサブネット2のCIDR範囲。
Type: String
Default: 10.1.1.0/24
MinLength: 9
MaxLength: 18
AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
# for RDS (Aurora)
EngineType: # DBエンジンタイプ。
Type: String
Default: aurora-mysql
MySQLMajorVersion: # MySQLメジャーヴァージョン。
Type: String
Default: 8.0
MySQLMinorVersion: # MySQLマイナーヴァージョン。
Type: String
Default: 3.02.2
MinCapacityForApplicationAutoscaling: # クラスター内のリードレプリカの最小台数。
Type: String
Default: 1
AllowedValues: [1,2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
MaxCapacityForApplicationAutoscaling: # クラスター内のリードレプリカの最大台数。
Type: String
Default: 2
AllowedValues: [1,2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
TargetValueForApplicationAutoscaling: # DBのAutoScaling閾値。
Type: String
Default: 70
ScaleInCooldownForApplicationAutoscaling: # スケールインのクールダウン値。
Type: Number
Default: 600
ScaleOutCooldownForApplicationAutoscaling: # スケールアウトのクールダウン値。
Type: Number
Default: 300
WriterAndReaderDBInstanceClass: # ライター或いはリーダーとして動く予定のDBインスタンスクラス。
Type: String
Default: db.r6g.large
CustomEPMemberDBInstanceClass: # 初期カスタムエンドポイント用のDBインスタンスのインスタンスクラス
Type: String
Default: db.r6g.large
AllowMajorVersionUpgrade: # メジャーバージョンのアップグレードを許可するかどうか。
Type: String
Default: false
AllowedValues: [true, false]
AutoMinorVersionUpgrade: # マイナーバージョンのアップグレードを許可するかどうか。
Type: String
Default: true
AllowedValues: [true, false]
PreferredMaintenanceWindow: # 夜間バッチ処理等との干渉を回避する為のメンテナンスウィンドウの設定。
Type: String
Default: Fri:18:00-Fri:19:00
CustomEndpointName: # カスタムエンドポイントの名前。
Type: String
Default: sample
NumOfCustomEPMemberDBinstances: # カスタムエンドポイントのメンバーになるインスタンスの初期台数。
Type: String
Default: 1
AllowedValues: [1, 2]
# ------------------------------------------------------------#
# Conditions
# ------------------------------------------------------------#
Conditions: # 初期にカスタムエンドポイントに追加されるインスタンスを何台必要とするかでリソース作成を分岐。
CaseNeedNumIs1: !Equals [ !Ref NumOfCustomEPMemberDBinstances, 1 ]
CaseNeedNumIs2: !Equals [ !Ref NumOfCustomEPMemberDBinstances, 2 ]
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
# IAM
# ------------------------------------------------------------#
MakeCustomEPFunctionRole: # カスタムエンドポイントを作成する為のLambda関数用のロール。
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: !Sub ${PJPrefix}-CreateAuroraCustomEndpointPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- rds:CreateDBClusterEndpoint
- rds:DescribeDBClusters
Resource:
- !Sub arn:aws:rds:${AWS::Region}:${AWS::AccountId}:cluster:${AuroraCluster}
- !Sub arn:aws:rds:${AWS::Region}:${AWS::AccountId}:cluster-endpoint:*
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-MakeCustomEPFunctionRole
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCidrBlock
InstanceTenancy: default
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-VPC
# ------------------------------------------------------------#
# Subnet
# ------------------------------------------------------------#
# プライベート
PrivateSubnet1a:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !Ref PrivateSubnet1aCidrBlock
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs ]
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-PrivateSubnet1a
PrivateSubnet1c:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !Ref PrivateSubnet1cCidrBlock
VpcId: !Ref VPC
AvailabilityZone: !Select [ 1, !GetAZs ]
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-PrivateSubnet1c
# ------------------------------------------------------------#
# RDS
# ------------------------------------------------------------#
# DBクラスター
AuroraCluster:
DeletionPolicy: Snapshot
Type: AWS::RDS::DBCluster
Properties:
DBClusterIdentifier: !Sub ${PJPrefix}-DBCluster
DBClusterParameterGroupName: !Ref AuroraDBClusterParameterGroup
DBSubnetGroupName: !Ref AuroraDBSubnetGroup
Engine: !Ref EngineType
EngineVersion: !Sub ${MySQLMajorVersion}.mysql_aurora.${MySQLMinorVersion}
StorageEncrypted: true
MasterUsername: admin
ManageMasterUserPassword: True
VpcSecurityGroupIds:
- !Ref AuroraDBSG
PreferredMaintenanceWindow: !Ref PreferredMaintenanceWindow
AvailabilityZones:
- !Select [ 0, !GetAZs ]
- !Select [ 1, !GetAZs ]
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-AuroraCluster
# DBクラスターパラメーターグループ
AuroraDBClusterParameterGroup:
Type: AWS::RDS::DBClusterParameterGroup
Properties:
Description: Aurora Cluster Parameter Group.
Family: !Sub ${EngineType}${MySQLMajorVersion}
Parameters:
time_zone: Asia/Tokyo
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-AuroraDBClusterParameterGroup
# DBパラメーターグループ
AuroraDBParameterGroup:
Type: AWS::RDS::DBParameterGroup
Properties:
Description: Aurora Parameter Group.
Family: !Sub ${EngineType}${MySQLMajorVersion}
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-AuroraDBParameterGroup
# DBサブネットグループ
AuroraDBSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupName: !Sub ${PJPrefix}-AuroraDBSubnetGroup
DBSubnetGroupDescription: Aurora SubnetGroup
SubnetIds:
- !Ref PrivateSubnet1a
- !Ref PrivateSubnet1c
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-AuroraDBSubnetGroup
# DBインスタンス
AuroraDBInstance1: # 初期にライターとなるインスタンス。
Type: AWS::RDS::DBInstance
Properties:
AllowMajorVersionUpgrade: !Ref AllowMajorVersionUpgrade
AutoMinorVersionUpgrade: !Ref AutoMinorVersionUpgrade
DBClusterIdentifier: !Ref AuroraCluster
DBInstanceClass: !Ref WriterAndReaderDBInstanceClass
DBParameterGroupName: !Ref AuroraDBParameterGroup
DBSubnetGroupName: !Ref AuroraDBSubnetGroup
Engine: !Ref EngineType
EngineVersion: !Sub ${MySQLMajorVersion}.mysql_aurora.${MySQLMinorVersion}
PubliclyAccessible: false
PreferredMaintenanceWindow: !Ref PreferredMaintenanceWindow
PromotionTier: 1
AvailabilityZone: !Select [ 0, !GetAZs ]
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-AuroraDBInstance1
AuroraDBInstance2: # リーダーとなるインスタンス。
DependsOn: AuroraDBInstance1
Type: AWS::RDS::DBInstance
Properties:
AllowMajorVersionUpgrade: !Ref AllowMajorVersionUpgrade
AutoMinorVersionUpgrade: !Ref AutoMinorVersionUpgrade
DBClusterIdentifier: !Ref AuroraCluster
DBInstanceClass: !Ref WriterAndReaderDBInstanceClass
DBParameterGroupName: !Ref AuroraDBParameterGroup
DBSubnetGroupName: !Ref AuroraDBSubnetGroup
Engine: !Ref EngineType
EngineVersion: !Sub ${MySQLMajorVersion}.mysql_aurora.${MySQLMinorVersion}
PubliclyAccessible: false
PreferredMaintenanceWindow: !Ref PreferredMaintenanceWindow
PromotionTier: 1
AvailabilityZone: !Select [ 1, !GetAZs ]
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-AuroraDBInstance2
CustomEPMemberDBInstance1: # リーダー且つカスタムエンドポイントのメンバーとなるインスタンス1。
DependsOn: AuroraDBInstance1
Type: AWS::RDS::DBInstance
Properties:
AllowMajorVersionUpgrade: !Ref AllowMajorVersionUpgrade
AutoMinorVersionUpgrade: !Ref AutoMinorVersionUpgrade
DBClusterIdentifier: !Ref AuroraCluster
DBInstanceClass: !Ref CustomEPMemberDBInstanceClass
DBParameterGroupName: !Ref AuroraDBParameterGroup
DBSubnetGroupName: !Ref AuroraDBSubnetGroup
Engine: !Ref EngineType
EngineVersion: !Sub ${MySQLMajorVersion}.mysql_aurora.${MySQLMinorVersion}
PubliclyAccessible: false
PreferredMaintenanceWindow: !Ref PreferredMaintenanceWindow
PromotionTier: 14
AvailabilityZone: !Select [ 1, !GetAZs ]
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-CustomEPMemberDBInstance
CustomEPMemberDBInstance2: # リーダー且つカスタムエンドポイントのメンバーとなるインスタンス2。(初期に二台目を希望する場合のみ作成。)
DependsOn: AuroraDBInstance1
Condition: CaseNeedNumIs2
Type: AWS::RDS::DBInstance
Properties:
AllowMajorVersionUpgrade: !Ref AllowMajorVersionUpgrade
AutoMinorVersionUpgrade: !Ref AutoMinorVersionUpgrade
DBClusterIdentifier: !Ref AuroraCluster
DBInstanceClass: !Ref CustomEPMemberDBInstanceClass
DBParameterGroupName: !Ref AuroraDBParameterGroup
DBSubnetGroupName: !Ref AuroraDBSubnetGroup
Engine: !Ref EngineType
EngineVersion: !Sub ${MySQLMajorVersion}.mysql_aurora.${MySQLMinorVersion}
PubliclyAccessible: false
PreferredMaintenanceWindow: !Ref PreferredMaintenanceWindow
PromotionTier: 14
AvailabilityZone: !Select [ 0, !GetAZs ]
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-CustomEPMemberDBInstance2
# ------------------------------------------------------------#
# ApplicationAutoScaling
# ------------------------------------------------------------#
# スケーラブルターゲット
ScalableTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
Properties:
MaxCapacity: !Ref MaxCapacityForApplicationAutoscaling
MinCapacity: !Ref MinCapacityForApplicationAutoscaling
RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/rds.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_
ServiceNamespace: rds
ScalableDimension: rds:cluster:ReadReplicaCount
ResourceId: !Sub cluster:${AuroraCluster}
# スケ-リングポリシー
ScalingPolicyDBCluster:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: !Sub ${AuroraCluster}-asg
PolicyType: TargetTrackingScaling
ScalingTargetId: !Ref ScalableTarget
TargetTrackingScalingPolicyConfiguration:
TargetValue: !Ref TargetValueForApplicationAutoscaling
PredefinedMetricSpecification:
PredefinedMetricType: RDSReaderAverageCPUUtilization
ScaleInCooldown: !Ref ScaleInCooldownForApplicationAutoscaling
ScaleOutCooldown: !Ref ScaleOutCooldownForApplicationAutoscaling
DisableScaleIn: False
# ------------------------------------------------------------#
# CustomResource
# ------------------------------------------------------------#
# カスタムリソース
CustomResourcePattern1: # 初期に作成されるカスタムエンドポイントのメンバーになるリーダーインスタンスは一台で良い場合。
Condition: CaseNeedNumIs1
DependsOn:
- AuroraDBInstance2
- CustomEPMemberDBInstance1
Type: Custom::CustomResource
Properties:
ServiceToken: !GetAtt MakeCustomEPFunction.Arn
CustomResourcePattern2: # 二台必要な場合。
Condition: CaseNeedNumIs2
DependsOn:
- AuroraDBInstance2
- CustomEPMemberDBInstance1
- CustomEPMemberDBInstance2
Type: Custom::CustomResource
Properties:
ServiceToken: !GetAtt MakeCustomEPFunction.Arn
# ------------------------------------------------------------#
# Lambda
# ------------------------------------------------------------#
# 関数
MakeCustomEPFunction: # カスタムエンドポイント作成+メンバーに追加。
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |
import boto3
import cfnresponse
import os
db_cluster_identifier = os.environ['DB_CLUSTER_IDENTIFIER']
db_cluster_custom_endpoint = os.environ['DB_CLUSTER_CUSTOM_ENDPOINT']
client = boto3.client('rds')
CREATE = 'Create'
response_data = {}
def lambda_handler(event, context):
try:
if event['RequestType'] == CREATE:
response = client.describe_db_clusters(
DBClusterIdentifier=db_cluster_identifier
)
Tier_14_instances = [member for member in response['DBClusters'][0]['DBClusterMembers'] if member['IsClusterWriter'] == False and member['PromotionTier'] == 14]
DBInstanceIdentifier_list =[]
for Tier_14_instance in Tier_14_instances:
DBInstanceIdentifier_list.append(Tier_14_instance['DBInstanceIdentifier'])
create_response = client.create_db_cluster_endpoint(
DBClusterIdentifier=db_cluster_identifier,
DBClusterEndpointIdentifier=db_cluster_custom_endpoint,
EndpointType='READER',
StaticMembers=DBInstanceIdentifier_list)
print(create_response)
response_data[db_cluster_custom_endpoint] = create_response['Endpoint']
cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)
except Exception as e:
print(e)
cfnresponse.send(event, context, cfnresponse.FAILED, response_data)
Environment:
Variables:
DB_CLUSTER_CUSTOM_ENDPOINT: !Ref CustomEndpointName
DB_CLUSTER_IDENTIFIER: !Ref AuroraCluster
FunctionName: !Sub ${PJPrefix}-MakeCustomEPfunction
Handler: index.lambda_handler
Runtime: python3.9
Role: !GetAtt MakeCustomEPFunctionRole.Arn
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-MakeCustomEPFunction
# ------------------------------------------------------------#
# SecurityGroup
# ------------------------------------------------------------#
# AuroraDBクラスター用。
AuroraDBSG:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref VPC
GroupName: !Sub ${PJPrefix}-AuroraDBSG
GroupDescription: Allow Inbound access.
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-AuroraDBSG
# Ingress
AuroraDBSGIngressMakeCustomEPFunctionSG:
Type: AWS::EC2::SecurityGroupIngress
Properties:
Description: Allow AuroraMySQL access from MakeCustomEPFunctionSG
FromPort: 3306
ToPort: 3306
IpProtocol: tcp
SourceSecurityGroupId: !Ref MakeCustomEPFunctionSG
GroupId: !GetAtt AuroraDBSG.GroupId
# カスタムエンドポイント作成関数用
MakeCustomEPFunctionSG:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref VPC
GroupName: !Sub ${PJPrefix}-MakeCustomEPFunctionSG
GroupDescription: Allow Outbound access.
Tags:
- Key: Name
Value: !Sub ${PJPrefix}-MakeCustomEPFunctionSG
# Egress
MakeCustomEPFunctionSGEgressforAuroraDBSG:
Type: AWS::EC2::SecurityGroupEgress
Properties:
Description: Allow AuroraMySQL access to MakeCustomEPFunctionSG.
GroupId: !GetAtt MakeCustomEPFunctionSG.GroupId
IpProtocol: tcp
FromPort: 3306
ToPort: 3306
DestinationSecurityGroupId: !GetAtt AuroraDBSG.GroupId
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
Outputs:
# ライター(クラスター)エンドポイント。
WriterEndpoint:
Value: !GetAtt AuroraCluster.Endpoint.Address
# リーダーエンドポイント。
ReadEndpoint:
Value: !GetAtt AuroraCluster.ReadEndpoint.Address
# カスタムエンドポイント(一台の場合)
CustomEndpoint:
Condition: CaseNeedNumIs1
Value: !GetAtt
- CustomResourcePattern1
- !Ref CustomEndpointName
# カスタムエンドポイント(二台の場合)
CustomEndpoint2:
Condition: CaseNeedNumIs2
Value: !GetAtt
- CustomResourcePattern2
- !Ref CustomEndpointName
スタック実行
スタック名と、一番上のPJPrefix欄に任意の文字(なんでもいいです)を入れて先へ進んでください。
※沢山あるパラメーターですがひとつを除いて全てデフォルト値が入っています。
※カスタムエンドポイントのメンバーとなる初期インスタンスを二台立ち上げたい場合は"NumOfCustomEPMemberDBinstances"というパラメーターを2に変更出来ます。
↓
↓
クラスターリソースが作成され、それぞれ意図した役割についています。
↓
カスタムエンドポイントが作成されました。
↓
無事に意図したインスタンスがメンバーになっています。
スタックの出力欄にもライター・リーダー・作成したカスタムのそれぞれが出力されています。
以上となります。
ポイントの説明
ポイントの説明
①初期にライター・リーダーとなるインスタンスは意図的に選択したい。
↓
AuroraDBInstance2:
DependsOn: AuroraDBInstance1
# 後略
※デメリット:
・DBインスタンスが段階的に作られるせいでスタック全体の完成に時間がかかる。
・恐らくあまり意味がない(元々他のインスタンスと役割が入れ替わる事が前提の概念の為)
②カスタムエンドポイントメンバーのインスタンスは出来る限り昇格して欲しくない。
(カスタムエンドポイントのメンバーが0になる可能性を極力少なくしたい。)
↓
CustomEPMemberDBInstance1:
Type: AWS::RDS::DBInstance
Properties:
# 中略
PromotionTier: 14
※15でもよかったのですが、オートスケーリングで立ち上がるリードレプリカは15である為14を設定。
※PromotionTierについては以下記事を参照
このPromotionTierが14である値を、Lambda関数内カスタムエンドポイントに追加するインスタンスかどうかの判断に使いました。
['PromotionTier'] == 14
③カスタムエンドポイントのメンバーになるインスタンスは単一障害点を避ける意味で、初期に作成台数を選択可能にしたい(一旦二台)。
Conditions:
CaseNeedNumIs1: !Equals [ !Ref NumOfCustomEPMemberDBinstances, 1 ]
CaseNeedNumIs2: !Equals [ !Ref NumOfCustomEPMemberDBinstances, 2 ]
CustomEPMemberDBInstance2:
DependsOn: AuroraDBInstance1
Condition: CaseNeedNumIs2
# 後略
CustomResourcePattern2: # 二台必要な場合。
Condition: CaseNeedNumIs2
# 後略
④のインスタンスクラスは割愛して、
最後に⑤のスケールの話ですが、可能であればそれぞれの役割毎にターゲットスケーリングが出来ればと思い、ドキュメントを確認しましたが…
Type: AWS::ApplicationAutoScaling::ScalableTarget
Properties:
# 中略
ScalableDimension: rds:cluster:ReadReplicaCount
結果はやはり難しいようでした。
という事で結果としてごちゃごちゃと手を入れた割には最適解は見出せずという結果に終わりました。
参考にした記事
最後に
負荷分散やクラスターという概念についてもっと理解を持ちたいと感じました。
お付き合いいただき有難うございました!
Discussion