目次
はじめに
こんにちは。クラウド事業部の西川です。
今回は前回のテンプレートからRDSをMulti-AZ DB Clusterに変更したテンプレートをご紹介します。
↓前回の記事はこちら
CloudFormationを初めて触る方は↓の記事にスタックの作成方法も記載してありますので是非ご覧ください。
構成図
EC2 Auto Scalingは希望する台数3、最小台数3、最大サイズ4、CPU平均使用率70%を保つ設定のターゲット追跡スケーリングポリシーです。
EC2にはSession Managerで接続できるようにしています。
SSH接続したい場合はセキュリティグループでSSHのインバウンドを許可してください。
また、CloudWatch LogsはEC2インスタンスの/var/log/messagesのログを収集します。
本記事のメインテーマでもあるMulti-AZ DB Clusterには下記の特徴があります。
・3つのAZに跨る冗長構成
・2つの読み取り可能なスタンバイインスタンス
・35 秒未満の自動フェイルオーバー
Multi-AZ DB ClusterとMulti-AZ DB Instanceの違いについては下記の記事が非常にわかりやすいです。
テンプレート
AWSTemplateFormatVersion: '2010-09-09' Description: Multi-AZ DB Cluster WordPress Blog Site Parameters: DBMasterName: Description: Database Master User Name Type : String Default: admin DBMasterPassword: Description: Database Master User Password Type : String DBName: Description: Database Name Type : String Default: wordpress EngineVersion: Description: Engine Version Type : String Default: 8.0.35 DBClusterInstanceClass: Type : String Default: db.m6gd.large AllocatedStorage: Type: Number Default: 20 EC2AMIId: Description: AMI ID Type : String Default: ami-0d0150aa305b7226d KeyName: Description: The EC2 Key Pair to allow SSH access to the instance Type: "AWS::EC2::KeyPair::KeyName" EnvironmentName: Type: String Default: r-nishikawa-CFn-WP Resources: # ------------------------------------------------------------# # VPC # ------------------------------------------------------------# VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 InstanceTenancy: default EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Sub ${EnvironmentName}-VPC # ------------------------------------------------------------# # Internet Gateway # ------------------------------------------------------------# InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub ${EnvironmentName}-VPC-IGW AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway # ------------------------------------------------------------# # Route Table # ------------------------------------------------------------# RouteTable: Type: AWS::EC2::RouteTable DependsOn: AttachGateway Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-VPC-RTB Route: Type: AWS::EC2::Route DependsOn: AttachGateway Properties: RouteTableId: !Ref RouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway # ------------------------------------------------------------# # Public Sunbet A # ------------------------------------------------------------# PublicSubnetA: Type: AWS::EC2::Subnet DependsOn: AttachGateway Properties: AvailabilityZone: "ap-northeast-1a" CidrBlock: 10.0.1.0/24 MapPublicIpOnLaunch: 'true' VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-VPC-PublicSubnet-A PublicRouteTableAssociationA: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetA RouteTableId: !Ref RouteTable # ------------------------------------------------------------# # Private Sunbet A # ------------------------------------------------------------# PrivateSubnetA: Type: AWS::EC2::Subnet Properties: AvailabilityZone: "ap-northeast-1a" CidrBlock: 10.0.2.0/24 MapPublicIpOnLaunch: 'false' VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-VPC-PrivateSubnet-A # ------------------------------------------------------------# # Public Sunbet C # ------------------------------------------------------------# PublicSubnetC: Type: AWS::EC2::Subnet DependsOn: AttachGateway Properties: AvailabilityZone: "ap-northeast-1c" CidrBlock: 10.0.3.0/24 MapPublicIpOnLaunch: 'true' VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-VPC-PublicSubnet-C PublicRouteTableAssociationC: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetC RouteTableId: !Ref RouteTable # ------------------------------------------------------------# # Private Sunbet C # ------------------------------------------------------------# PrivateSubnetD: Type: AWS::EC2::Subnet Properties: AvailabilityZone: "ap-northeast-1c" CidrBlock: 10.0.4.0/24 MapPublicIpOnLaunch: 'false' VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-VPC-PrivateSubnet-C # ------------------------------------------------------------# # Public Sunbet D # ------------------------------------------------------------# PublicSubnetD: Type: AWS::EC2::Subnet DependsOn: AttachGateway Properties: AvailabilityZone: "ap-northeast-1d" CidrBlock: 10.0.5.0/24 MapPublicIpOnLaunch: 'true' VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-VPC-PublicSubnet-D PublicRouteTableAssociationD: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetD RouteTableId: !Ref RouteTable # ------------------------------------------------------------# # Private Sunbet D # ------------------------------------------------------------# PrivateSubnetC: Type: AWS::EC2::Subnet Properties: AvailabilityZone: "ap-northeast-1d" CidrBlock: 10.0.6.0/24 MapPublicIpOnLaunch: 'false' VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-VPC-PrivateSubnet-D # ------------------------------------------------------------# # ALB Security Group # ------------------------------------------------------------# ALBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub ${EnvironmentName}-ALB-SG GroupDescription: Allow HTTP and HTTPS access from internet VpcId: !Ref VPC SecurityGroupIngress: # http - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: "0.0.0.0/0" # https - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: "0.0.0.0/0" Tags: - Key: Name Value: !Sub ${EnvironmentName}-ALB-SG # ------------------------------------------------------------# # ALB # ------------------------------------------------------------# ApplicationLoadBalancer: Type : AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub ${EnvironmentName}-ALB Scheme: "internet-facing" SecurityGroups: - !Ref ALBSecurityGroup Subnets: - !Ref PublicSubnetA - !Ref PublicSubnetC - !Ref PublicSubnetD Tags: - Key: Name Value: !Sub ${EnvironmentName}-ALB # ------------------------------------------------------------# # ALB Target Group # ------------------------------------------------------------# ALBTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 30 HealthCheckPath: "/healths/wp-check" HealthCheckPort: 80 HealthCheckProtocol: HTTP HealthyThresholdCount: 5 Name: !Sub ${EnvironmentName}-ALB-TG Port: 80 Protocol: HTTP HealthCheckTimeoutSeconds: 5 Tags: - Key: Name Value: !Sub ${EnvironmentName}-ALB-TG TargetType: instance UnhealthyThresholdCount: 2 VpcId: !Ref VPC # ------------------------------------------------------------# # ALB Listner # ------------------------------------------------------------# ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - TargetGroupArn: !Ref ALBTargetGroup Type: forward LoadBalancerArn: !Ref ApplicationLoadBalancer Port: 80 Protocol: HTTP # ------------------------------------------------------------# # EC2 Auto Scaling Group # ------------------------------------------------------------# EC2AutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: !Sub "${EnvironmentName}-ASG" DesiredCapacity: '3' MinSize: '3' MaxSize: '4' VPCZoneIdentifier: - !Ref PublicSubnetA - !Ref PublicSubnetC - !Ref PublicSubnetD LaunchTemplate: LaunchTemplateId: !Ref EC2LaunchTemplate Version: !GetAtt EC2LaunchTemplate.LatestVersionNumber TargetGroupARNs: - !Ref ALBTargetGroup HealthCheckType: ELB HealthCheckGracePeriod: 300 Tags: - Key: Name Value: !Sub ${EnvironmentName}-EC2-ASG PropagateAtLaunch: true # ------------------------------------------------------------# # EC2 Auto Scaling Policy # ------------------------------------------------------------# EC2AutoScalingPolicy: Type: AWS::AutoScaling::ScalingPolicy Properties: AutoScalingGroupName: !Ref EC2AutoScalingGroup PolicyType: TargetTrackingScaling TargetTrackingConfiguration: PredefinedMetricSpecification: PredefinedMetricType: ASGAverageCPUUtilization TargetValue: 70 # ------------------------------------------------------------# # EC2 Security Group # ------------------------------------------------------------# EC2SecurityGroup: Type: AWS::EC2::SecurityGroup DependsOn: ALBSecurityGroup Properties: GroupName: !Sub ${EnvironmentName}-EC2-SG GroupDescription: Allow HTTP and HTTPS from ALBSecurityGroup VpcId: !Ref VPC SecurityGroupIngress: # HTTP - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !Ref ALBSecurityGroup # HTTPS - IpProtocol: tcp FromPort: 443 ToPort: 443 SourceSecurityGroupId: !Ref ALBSecurityGroup Tags: - Key: Name Value: !Sub ${EnvironmentName}-EC2-SG # ------------------------------------------------------------# # EC2 Instance Role # ------------------------------------------------------------# EC2InstanceRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${EnvironmentName}-EC2InstanceRole AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: [ec2.amazonaws.com, ssm.amazonaws.com] Action: 'sts:AssumeRole' Path: "/" ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore Policies: - PolicyName: !Sub ${EnvironmentName}-EC2-Policy-V1 PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - logs:DescribeLogStreams Resource: '*' # ------------------------------------------------------------# # Instance Profile # ------------------------------------------------------------# InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref EC2InstanceRole # ------------------------------------------------------------# # EC2 Launch Template # ------------------------------------------------------------# EC2LaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: !Sub ${EnvironmentName}-Launch-Template LaunchTemplateData: IamInstanceProfile: Arn: !GetAtt InstanceProfile.Arn ImageId: !Ref EC2AMIId KeyName: !Ref KeyName InstanceType: t2.micro SecurityGroupIds: - !Ref EC2SecurityGroup UserData: Fn::Base64: !Sub | #!/bin/bash set -e yum -y update amazon-linux-extras install php7.2 -y yum -y install mysql httpd php-mbstring php-xml gd php-gd systemctl enable httpd.service systemctl start httpd.service wget http://ja.wordpress.org/latest-ja.tar.gz tar zxvf latest-ja.tar.gz cp -r wordpress/* /var/www/html/ chown apache:apache -R /var/www/html cd /var/www/html/ mkdir healths cd healths touch wp-check # Amazon CloudWatch Agentのインストールと設定 yum install -y amazon-cloudwatch-agent INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id) cat <<EOF > /opt/aws/amazon-cloudwatch-agent/bin/config.json { "agent": { "run_as_user": "root" }, "logs": { "logs_collected": { "files": { "collect_list": [ { "file_path": "/var/log/messages", "log_group_name": "${EnvironmentName}/logs", "log_stream_name": "$INSTANCE_ID", "timezone": "Local" } ] } } } } EOF /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json -s BlockDeviceMappings: - DeviceName: /dev/xvda Ebs: VolumeSize: 8 VolumeType: gp2 TagSpecifications: - ResourceType: instance Tags: - Key: Name Value: !Sub ${EnvironmentName}-EC2-Instance # ------------------------------------------------------------# # Database Subnet Group # ------------------------------------------------------------# RDSDBSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: WP-RDS-SubnetGroup DBSubnetGroupName: WP-RDS-SubnetGroup SubnetIds: - !Ref PrivateSubnetA - !Ref PrivateSubnetC - !Ref PrivateSubnetD Tags: - Key: Name Value: !Sub ${EnvironmentName}-RDS-SubnetGroup # ------------------------------------------------------------# # RDS Security Group # ------------------------------------------------------------# RDSSG: Type: AWS::EC2::SecurityGroup Properties: GroupName: WP-RDS-SG GroupDescription: Allow Request from WebServer VpcId: !Ref VPC SecurityGroupIngress: # http - IpProtocol: tcp FromPort: 3306 ToPort: 3306 SourceSecurityGroupId: !Ref EC2SecurityGroup Tags: - Key: Name Value: !Sub ${EnvironmentName}-RDS-SG # ------------------------------------------------------------# # RDS Multi-AZ DB Cluster # ------------------------------------------------------------# MultiAZDBCluster: Type: 'AWS::RDS::DBCluster' Properties: AllocatedStorage: !Ref AllocatedStorage DatabaseName: !Ref DBName DBClusterIdentifier: !Sub ${EnvironmentName}-DBCluster DBClusterInstanceClass: !Ref DBClusterInstanceClass Engine: mysql EngineVersion: !Ref EngineVersion MasterUsername: !Ref DBMasterName MasterUserPassword: !Ref DBMasterPassword DBSubnetGroupName: !Ref RDSDBSubnetGroup VpcSecurityGroupIds: - !Ref RDSSG BackupRetentionPeriod: 1 PubliclyAccessible: false StorageEncrypted: true StorageType: gp3
まとめ
Multi-AZ DB ClusterはMulti-AZ DB Instanceよりもコストは高くなりますが、その分メリットもある構成です。
高可用性が求められ、素早いフェイルオーバーが求められる場合には有力な選択肢になります。
ご参考になれば幸いです。