目次
はじめに
こんにちは。クラウド事業部の西川です。
今回はELB(ALB)とEC2、RDSを使用したWeb3層構造のWordPress環境のCloudFormationテンプレートとデプロイ方法をご紹介します。
EC2インスタンスへはSession Managerで接続できるようにしています。
構成図
テンプレート
AWSTemplateFormatVersion: '2010-09-09' Description: Single-AZ WordPress Blog Site Parameters: DatabaseMasterName: Description: Database Master User Name Type : String Default: admin DatabaseMasterPassword: Description: Database Master User Password Type : String DatabaseName: Description: Database Name Type : String Default: wordpress EngineVersion: Description: Engine Version Type : String Default: 8.0.35 EC2AMIId: Description: AMI ID Type : String Default: ami-0d0150aa305b7226d EnvironmentName: Type: String Default: Test-CFn-WP KeyName: Description: The EC2 Key Pair to allow SSH access to the instance Type: "AWS::EC2::KeyPair::KeyName" 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 # ------------------------------------------------------------# PrivateSubnetC: 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 # ------------------------------------------------------------# # 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 Tags: - Key: Name Value: !Sub ${EnvironmentName}-ALB # ------------------------------------------------------------# # Target Group # ------------------------------------------------------------# ALBTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckPath: /healths/wp-check HealthCheckEnabled: True Name: !Sub ${EnvironmentName}-ALB-TG Port: 80 Protocol: HTTP Tags: - Key: Name Value: !Sub ${EnvironmentName}-ALB-TG Targets: - Id: !Ref EC2Instance Port: 80 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 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 Role for SSM # ------------------------------------------------------------# EC2RoleforSSM: Type: AWS::IAM::Role Properties: RoleName: !Sub ${EnvironmentName}-SSM-role AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore # ------------------------------------------------------------# # EC2 Instance Profile # ------------------------------------------------------------# EC2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref EC2RoleforSSM # ------------------------------------------------------------# # EC2 # ------------------------------------------------------------# EC2Instance: Type: AWS::EC2::Instance Properties: AvailabilityZone: "ap-northeast-1a" BlockDeviceMappings: - DeviceName: /dev/xvda Ebs: VolumeSize: 8 VolumeType: gp2 ImageId: !Ref EC2AMIId InstanceInitiatedShutdownBehavior: 'stop' InstanceType: t2.micro IamInstanceProfile: !Ref EC2InstanceProfile KeyName: !Ref KeyName SecurityGroupIds: - !Ref EC2SecurityGroup SubnetId: !Ref PublicSubnetA Tenancy: default Tags: - Key: Name Value: !Sub ${EnvironmentName}-EC2-Instance UserData: Fn::Base64: | #!/bin/bash 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 # ------------------------------------------------------------# # Database Subnet Group # ------------------------------------------------------------# RDSDBSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: RDS-SubnetGroup DBSubnetGroupName: !Sub ${EnvironmentName}-RDS-SubnetGroup SubnetIds: - !Ref PrivateSubnetA - !Ref PrivateSubnetC Tags: - Key: Name Value: !Sub ${EnvironmentName}-RDS-SubnetGroup # ------------------------------------------------------------# # RDS Security Group # ------------------------------------------------------------# RDSSG: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub ${EnvironmentName}-RDS-SG GroupDescription: Allow Request from WebServer VpcId: !Ref VPC SecurityGroupIngress: # http - IpProtocol: tcp FromPort: 3306 ToPort: 3306 SourceSecurityGroupId: !Ref EC2SecurityGroup Tags: - Key: !Sub ${EnvironmentName}-Name Value: !Sub ${EnvironmentName}-RDS-SG # ------------------------------------------------------------# # RDS # ------------------------------------------------------------# RDSDatabase: Type: AWS::RDS::DBInstance Properties: AllocatedStorage: 20 AllowMajorVersionUpgrade: false AutoMinorVersionUpgrade: false AvailabilityZone: ap-northeast-1a BackupRetentionPeriod: 0 DBInstanceClass: db.t3.micro DBInstanceIdentifier: !Sub ${EnvironmentName}-RDS-Database DBName: !Ref DatabaseName DBSubnetGroupName: !Ref RDSDBSubnetGroup DeleteAutomatedBackups: false DeletionProtection: false Engine: mysql EngineVersion: !Ref EngineVersion MasterUsername: !Ref DatabaseMasterName MasterUserPassword: !Ref DatabaseMasterPassword MaxAllocatedStorage: 1000 MultiAZ: false PubliclyAccessible: false StorageEncrypted: false StorageType: gp2 Tags: - Key: Name Value: !Sub ${EnvironmentName}-RDS-Database VPCSecurityGroups: - !Ref RDSSG
スタック作成
上記のテンプレートをテキストエディタなどでYAML形式で保存してください。
AWSコンソールからCloudFormation(東京リージョン)に移動し「スタックの作成」→「新しいリソースを使用 (標準)」をクリックしてください。
- 下記の画面で「既存のテンプレートを選択」と「テンプレートファイルのアップロード」を選択し、「ファイルの選択」をクリックしYAMLファイルをアップロードしてください。
「次へ」をクリックし、下記の画面で任意の「スタック名」と「DatabaseMasterPassword」を入力し、「KeyName」でキーペアを選択してください。 ※「EC2AMIID」と「EngineVersion」はデフォルトで記載されているものが使用できない場合があるので、EC2とRDSの作成画面でそれぞれAmazon Linux 2のAMI IDとMySQLのエンジンバージョンを確認して入力してください。
次のページのスタックオプションの設定はそのままで問題ありません。
最後に「確認して作成」画面が表示されます。ここで設定内容を確認し、下記の「AWS CloudFormation によって IAM リソースがカスタム名で作成される場合があることを承認します。」のチェックボックスにチェックを入れてください。
送信ボタンを押せばスタックの作成が開始されます。
問題がなければ下記のように「CREATE_COMPLETE」になるはずです。
動作確認
スタックの作成が完了したらブラウザからアクセスしてみましょう。
DNS名はロードバランサの詳細から確認できます。
下記の画面が表示されればOKです。
続いてSession ManagerでEC2インスタンスに接続してみましょう。
作成したEC2インスタンスを選択し、「インスタンスの状態」の左にある「接続」をクリックしてください。
下記の画面が表示されれば接続可能です。
※SSHで接続したい場合はEC2のセキュリティグループでSSHのインバウンド通信を許可する必要があります。
スタック削除
CloudFormationではスタック単位でのリソースの一括削除が可能です。
CloudFormationに移動し、「削除」をクリックしてください。
確認画面が表示されるので、再び「削除」をクリックしてください。
まとめ
ITインフラの効率的な運用にIaC(Infrastructure as Code)はもはや必須であり、CloudFormationはAWS環境の運用において強力な武器となります。
また、個人で検証環境を作成する際にも非常に便利です。
本ブログのテンプレートは初歩的なものですので、これを色々いじったりリソースを追加したりすることでよりAWSとCloudFormationの理解が深まると思います。
この機会にCloudFormationの沼に飛び込んでみてはいかがでしょうか?
お知らせ
APCはAWS Advanced Tier Services(アドバンストティアサービスパートナー)認定を受けております。
その中で私達クラウド事業部はAWSなどのクラウド技術を活用したSI/SESのご支援をしております。
www.ap-com.co.jp
https://www.ap-com.co.jp/service/utilize-aws/
また、一緒に働いていただける仲間も募集中です!
今年もまだまだ組織規模拡大中なので、ご興味持っていただけましたらぜひお声がけください。