📝

1クリックでWordPressブログを構築する(CloudFormation)

2021/01/29に公開

背景

以下の記事で、AWSを使ってWordPressサイトを構築した。
https://zenn.dev/soshimiyamoto/articles/7d8b31aefab804

こちらでは、AWSのマネージメントコンソールを使って環境を構築したが、マネージメントコンソールを使って構築すると以下のようなデメリットがある。

  • 設定が複雑になってくると、セキュリティやルーティングの設定の関連性がわからなくなってくる可能性がある。
  • 管理が面倒
  • 一度削除すると、再度構築するのが面倒

上記の理由からも、近年ではコードでインフラを管理するInfrastructure as Code (IaC)が導入されてきている。
そこで今回は、上記記事で構築したWordPressブログの環境をAWSのIaCサービスであるCloudFormationを使って構築してみた。

CloudFormationとは

AWSのインフラ環境/リソースをコードで管理することができ、それを用いて一括でリソースを起動/削除が可能となるAWSのサービスである。


押さえておきたいポイントは以下。

  • YAML/JSONで管理する。
  • YAML/JSONで作成したテンプレートから、スタックを作成する。
  • スタックとは、テンプレートによって起動されるリソースの集合のこと。

これくらいだろうか。
細かい話は以下にわかりやすくまとめってあったのでそちらを参照していただきたい。
https://dev.classmethod.jp/articles/cloudformation-beginner01/

構成


今回作成を目指す構成

今回作成を目指す構成は上記の図の通り。

簡単なAWSの構成で、WordPressをインストールしたEC2, RDS, Internet Gateway, Application Load Balancer (ALB) からなる。

設定を行うため、EC2へはインターネットからSSHで接続できるようにしておき、実際のブログへのアクセスはALB経由でHTTPで通信する。
※EC2へインターネットからSSH接続できることに関してセキュリティ面で問題はあるが今回は目を瞑ることにする。

ALBは実際なくても良いが、今後Multi-AZ構成を取ることを想定した場合に必要となるため利用する。

実際に構築してみる

0. 事前準備

  • EC2へSSH接続するためのキーペアは事前に用意しておく。
     詳細は割愛する。

1. テンプレートの作成

実際に作成したテンプレートは以下

wordpress_template.yaml
AWSTemplateFormatVersion: '2010-09-09'

Description:
  Create WordPress Blog Site

Parameters:
  KeyName:
    Description: The EC2 Key Pair to allow SSH access to the instance
    Type: "AWS::EC2::KeyPair::KeyName"
  EC2AMIId:
    Description: AMI ID
    Type : String
    Default: ami-01748a72bed07727c
  DatabaseName:
    Description: Database Name
    Type : String
    Default: wordpress
  DatabaseMasterName:
    Description: Database Master User Namee
    Type : String
    Default: wordpress
  DatabaseMasterPassword:
    Description: Database Master User Password
    Type : String

Resources:

  # ------------------------------------------------------------#
  #  VPC
  # ------------------------------------------------------------#
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      InstanceTenancy: default
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
      - Key: Name
        Value: MyVPC
  
  # ------------------------------------------------------------#
  #  Internet Gateway
  # ------------------------------------------------------------#
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Name
        Value: My-InternetGateway
  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: My-RouteTable
  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: PublicSubnetA
  PublicRouteTableAssociation:
    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: PrivateSubnetA

  # ------------------------------------------------------------#
  #  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: PublicSubnetC

  # ------------------------------------------------------------#
  #  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: PrivateSubnetC

  # ------------------------------------------------------------#
  #  ALB Security Group
  # ------------------------------------------------------------#
  AlbSG1:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: ALB-SG-1
      GroupDescription: Allow HTTP access from internet
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # http
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: "0.0.0.0/0"
      Tags: 
        - Key: Name
          Value: ALB-SG-1
  
  # ------------------------------------------------------------#
  #  ALB
  # ------------------------------------------------------------#
  ApplicationLoadBalancer:
    Type : AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: My-ALB-1
      Scheme: "internet-facing"
      SecurityGroups:
        - !Ref AlbSG1
      # At least two subnet is needed
      Subnets:
        - !Ref PublicSubnetA
        - !Ref PublicSubnetC
      Tags: 
        - Key: Name
          Value: My-ALB-1

  # ------------------------------------------------------------#
  #  EC2 Security Group
  # ------------------------------------------------------------#
  WebSG1:
    Type: AWS::EC2::SecurityGroup
    DependsOn: AlbSG1
    Properties:
      GroupName: Web-SG-1
      GroupDescription: Allow SSH from Internet
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # ssh
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        # HTTP
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref AlbSG1
      Tags: 
        - Key: Name
          Value: Web-SG-1
  
  # ------------------------------------------------------------#
  #  EC2
  # ------------------------------------------------------------#
  WebServer: 
    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
      KeyName: !Ref KeyName
      SecurityGroupIds: 
        - !Ref WebSG1
      SubnetId: !Ref PublicSubnetA
      Tenancy: default
      Tags: 
        - Key: Name
          Value: WebServer
      UserData:
        Fn::Base64: |
          #!/bin/bash
          echo "===========yum -y install httpd==========="
          yum -y update
          echo "===========amazon-linux-extras install php7.2 -y==========="
          amazon-linux-extras install php7.2 -y
          echo "===========yum -y install mysql httpd php-mbstring php-xml gd php-gd==========="
          yum -y install mysql httpd php-mbstring php-xml gd php-gd
          echo "===========systemctl enable/start httpd.service ==========="
          systemctl enable httpd.service
          systemctl start httpd.service
          echo "=========== http://ja.wordpress.org/latest-ja.tar.gz ~/ ==========="
          wget http://ja.wordpress.org/latest-ja.tar.gz
          echo "=========== tar zxvf ~/latest-ja.tar.gz ==========="
          tar zxvf latest-ja.tar.gz
          echo "=========== cp -r wordpress/* /var/www/html/ ==========="
          cp -r wordpress/* /var/www/html/
          chown apache:apache -R /var/www/html
          cd /var/www/html/
          mkdir healthcheck
          cd healthcheck
          touch check

  # ------------------------------------------------------------#
  #  Target Group 
  # ------------------------------------------------------------#
  MyTG1:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      # Health check enabled must be true for target groups with target type 'instance' 
      HealthCheckPath: /healthcheck/check
      HealthCheckEnabled: True
      Name: My-TG-1
      Port: 80
      Protocol: HTTP
      Tags:
        - Key: Name
          Value: My-TG-1
      Targets:
        # If the target type is instance, you cannot override the Availability Zone
        - Id: !Ref WebServer
          Port: 80
      VpcId: !Ref VPC
  
  # ------------------------------------------------------------#
  #  ALB Listner
  # ------------------------------------------------------------#
  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - TargetGroupArn: !Ref MyTG1
          Type: forward
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP

  # ------------------------------------------------------------#
  #  Database Subnet Group
  # ------------------------------------------------------------#
  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties: 
      DBSubnetGroupDescription: My-SubnetGroup
      DBSubnetGroupName: My-SubnetGroup
      SubnetIds: 
        - !Ref PrivateSubnetA
        - !Ref PrivateSubnetC
      Tags: 
        - Key: Name
          Value: My-SubnetGroup

  # ------------------------------------------------------------#
  #  RDS Security Group
  # ------------------------------------------------------------#
  RDSSG1:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: RDS-SG-1
      GroupDescription: Allow Request from WebServer
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # http
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          SourceSecurityGroupId: !Ref WebSG1
      Tags: 
        - Key: Name
          Value: RDS-SG-1

  # ------------------------------------------------------------#
  #  RDS 
  # ------------------------------------------------------------#
  Database:
    Type: AWS::RDS::DBInstance
    Properties: 
      AllocatedStorage: 20
      AllowMajorVersionUpgrade: false
      AutoMinorVersionUpgrade: false
      AvailabilityZone: ap-northeast-1a
      BackupRetentionPeriod: 0
      DBInstanceClass: db.t3.micro
      DBInstanceIdentifier: database-1
      DBName: !Ref DatabaseName
      DBSubnetGroupName: !Ref DBSubnetGroup
      DeleteAutomatedBackups: false
      DeletionProtection: false
      Engine: mysql
      EngineVersion: 8.0.20
      MasterUsername: !Ref DatabaseMasterName
      MasterUserPassword: !Ref DatabaseMasterPassword
      MaxAllocatedStorage: 1000
      MultiAZ: false
      PubliclyAccessible: false
      StorageEncrypted: false
      StorageType: gp2
      Tags: 
        - Key: Name
          Value: My-RDS-1
      VPCSecurityGroups: 
        - !Ref RDSSG1

基本的には画面でポチポチと設定する内容を記入していけばよい。
公式のドキュメントを参考にした。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html

2. スタックの作成

① テンプレートの指定

  • サービス > CloudFormationを選択し、「スタックの作成」を押下
  • 以下の通りテンプレートをアップロードする。

② スタックの詳細を指定

  • 以下のように設定
項目 設定値
スタックの名前 MyStack
DatabaseMasterName wordpress
DatabaseMasterPassword 任意のパスワード
DatabaseName wordpress
EC2AMIId ami-01748a72bed07727c
KeyName MyKeyPair
※スタックの名前以外は、templateでParametersとして自分で設定できるものである。

③ スタックオプションの設定

  • 何も記入せず「次へ」

④ レビュー

  • 問題なければ「スタックの作成」
  • 完了するまで5分くらいかかったが、以下のようにCREATE_COMPLETEと表示されれば完了

3. 動作確認

完了したら、さっそくサイトにアクセスしてみる。

  • サービス > EC2 のロードバランサーからDNS名をコピー

  • ブラウザに張り付け

上記のようにWordPressの画面が表示され、その後、画面の指示に従ってWordPressのインストールが完了した。

  • ちなみに、EC2へもSSHでログインが可能であった。

  • ユーザーデータで指定したApacheインストールやWordPressのダウンロード、ヘルスチェックファイルの作成もうまくいっているようだ。

なお、ユーザーデータで指定したコマンドのログは/var/log/cloud-init-output.logに出力されている。

テンプレートの詳細

簡単であるが、テンプレートについて解説する。
一個一個の設定を説明するのはAWSのドキュメントに任せて、ポイント/自分が悩んだところなどを記載する。

パラメータの設定

Parameters:
  KeyName:
    Description: The EC2 Key Pair to allow SSH access to the instance
    Type: "AWS::EC2::KeyPair::KeyName"
  EC2AMIId:
    Description: AMI ID
    Type : String
    Default: ami-01748a72bed07727c
  DatabaseName:
    Description: Database Name
    Type : String
    Default: wordpress
  DatabaseMasterName:
    Description: Database Master User Namee
    Type : String
    Default: wordpress
  DatabaseMasterPassword:
    Description: Database Master User Password
    Type : String

下記は、ユーザーが任意に作成できるパラメータであり、Parametersで作成が可能である。
ここで設定したパラメータは画面でスタックを作成するときに、入力できるようになる。

ここでは、EC2にSSH接続するためのキーペアやAMIのID、データベース名、データベースのマスターユーザー名、パスワードをパラメータとして設定した。


VPC

  # ------------------------------------------------------------#
  #  VPC
  # ------------------------------------------------------------#
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      InstanceTenancy: default
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
      - Key: Name
        Value: MyVPC
  • AWS::EC2::VPCでVPCを作成できる。
  • CidrBlockさえ指定すれば構築できる。

Internet Gateway

  # ------------------------------------------------------------#
  #  Internet Gateway
  # ------------------------------------------------------------#
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Name
        Value: My-InternetGateway
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  • AWS::EC2::InternetGatewayで作成できる。特に設定値はなし。
  • VPCGatewayAttachementで、VPCにInternet Gatewayをアタッチする、
     プロパティでVPCのIDやInternet GatewayのIDを指定する。なお、!Refを使うとリソースのIDなどが参照できる。

Route Table

  # ------------------------------------------------------------#
  #  Route Table
  # ------------------------------------------------------------#
  RouteTable:
    Type: AWS::EC2::RouteTable
    DependsOn: AttachGateway
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: My-RouteTable
  Route:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref RouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  • AWS::EC2::RouteTableでルートテーブルを作成する。
  • Dependonにリソースを指定すると、そこで指定したリソースの作成直後にリソースを生成する。ここでは、Route TableはInternet GatewayがVPCにアタッチされた直後に作成されることを意味する。
  • AWS::EC2::Routeでルーティングの設定を追加する。
    ルーティングに関してはRouteTableのプロパティでは設定できないことに注意したい。
    送信先のiPをDestinationCidrBlockプロパティで指定し、ターゲットをGatewayIdで指定した。送信元をIPv6にしたい場合は、DestinationIpv6CidrBlockで指定する。ターゲットをInternet Gateway以外にしたい場合は、InstanceId, NatGatewayIdプロパティなどを指定できる。

Subnet

  # ------------------------------------------------------------#
  #  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: PublicSubnetA
  PublicRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetA
      RouteTableId: !Ref RouteTable
  • AWS::EC2::Subnetで作成する。プロパティでVPCやアベイラビリティゾーンを指定する。
  • AWS::EC2::SubnetRouteTabelAssociationでサブネットとRoute Tableを紐づけるための設定を追加することができる。

  # ------------------------------------------------------------#
  #  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: PrivateSubnetA

その他のSubnetについても同様に作成する。
ただし、Internet Gatewayへのルーティングは行わない。
AZ-Cは省略


Application Load Balancer

  # ------------------------------------------------------------#
  #  ALB Security Group
  # ------------------------------------------------------------#
  AlbSG1:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: ALB-SG-1
      GroupDescription: Allow HTTP access from internet
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # http
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: "0.0.0.0/0"
      Tags: 
        - Key: Name
          Value: ALB-SG-1
  • 先に、ALBにアタッチするセキュリティグループを作成する。
  • AWS::EC2::SecurityGroupで作成する。
  • インターネットからのアクセスを許可するので、すべてのTCPの80番ポート通信を許可する設定とする。

  # ------------------------------------------------------------#
  #  ALB
  # ------------------------------------------------------------#
  ApplicationLoadBalancer:
    Type : AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: My-ALB-1
      Scheme: "internet-facing"
      SecurityGroups:
        - !Ref AlbSG1
      # At least two subnet is needed
      Subnets:
        - !Ref PublicSubnetA
        - !Ref PublicSubnetC
      Tags: 
        - Key: Name
          Value: My-ALB-1
  • AWS::ElasticLoadBalancingV2::LoadBalancerでALBを作成する。
  • SecurityGroupプロパティで、先ほど作ったALBのセキュリティグループをアタッチする。
  • SubnetはPublic Subnet A, Cの二つを指定する。(※2つないとダメ)

EC2

  # ------------------------------------------------------------#
  #  EC2 Security Group
  # ------------------------------------------------------------#
  WebSG1:
    Type: AWS::EC2::SecurityGroup
    DependsOn: AlbSG1
    Properties:
      GroupName: Web-SG-1
      GroupDescription: Allow SSH from Internet
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # ssh
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        # HTTP
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref AlbSG1
      Tags: 
        - Key: Name
          Value: Web-SG-1
  • ALB同様、EC2にアタッチするセキュリティグループを作成する。
  • SSHはインターネットからのアクセスを許可するので、TCPの22番ポートのCIDRは0.0.0.0/0。
  • HTTPは、ALBからの通信のみ許可したいので、CidrIpではなくSourceSecurityGroupIdを設定する。
  # ------------------------------------------------------------#
  #  EC2
  # ------------------------------------------------------------#
  WebServer: 
    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
      KeyName: !Ref KeyName
      SecurityGroupIds: 
        - !Ref WebSG1
      SubnetId: !Ref PublicSubnetA
      Tenancy: default
      Tags: 
        - Key: Name
          Value: WebServer
      UserData:
        Fn::Base64: |
          #!/bin/bash
          echo "===========yum -y install httpd==========="
          yum -y update
          echo "===========amazon-linux-extras install php7.2 -y==========="
          amazon-linux-extras install php7.2 -y
          echo "===========yum -y install mysql httpd php-mbstring php-xml gd php-gd==========="
          yum -y install mysql httpd php-mbstring php-xml gd php-gd
          echo "===========systemctl enable/start httpd.service ==========="
          systemctl enable httpd.service
          systemctl start httpd.service
          echo "=========== http://ja.wordpress.org/latest-ja.tar.gz ~/ ==========="
          wget http://ja.wordpress.org/latest-ja.tar.gz
          echo "=========== tar zxvf ~/latest-ja.tar.gz ==========="
          tar zxvf latest-ja.tar.gz
          echo "=========== cp -r wordpress/* /var/www/html/ ==========="
          cp -r wordpress/* /var/www/html/
          chown apache:apache -R /var/www/html
          cd /var/www/html/
          mkdir healthcheck
          cd healthcheck
          touch check
  • EC2インスタンスは、AWS::EC2::Instanceで作成する。

  • BlockDeviceMappingsプロパティで/dev/xvdaにEBSボリュームをアタッチできる。

  • KeyName: !Ref KeyNameで、Parametersで指定したKeyPairを設定する。

  • UserDataで、ユーザーデータを設定する。
    ここで、apacheのインストールやwordpressのダウンロード、ヘルスチェックファイルの作成を子なっている。
    なお、ユーザーデータを記載する際は、スクリプトをBase64エンコードする必要があるため、 Fn::Base64でエンコードする。

  • セキュリティグループを指定する際は、SecurityGroupIdsプロパティを利用する。
    他にもSecurityGroupsなるプロパティがあるがこれを利用するとエラーとなった。
    ドキュメントを参照すると以下が記載されている。

[EC2-Classic、デフォルト VPC] セキュリティグループの名前。デフォルト以外の VPC の場合は、代わりにセキュリティグループ ID を使用する必要があります。

上記のような、EC2-Classicや、デフォルトVPC以外はSecurityGroupIdsを利用する。
つまり、ほとんどの場合こっちでよいと思われる。



ALBとEC2の接続

  # ------------------------------------------------------------#
  #  Target Group 
  # ------------------------------------------------------------#
  MyTG1:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckPath: /healthcheck/check
      HealthCheckEnabled: True
      Name: My-TG-1
      Port: 80
      Protocol: HTTP
      Tags:
        - Key: Name
          Value: My-TG-1
      Targets:
        - Id: !Ref WebServer
          Port: 80
      VpcId: !Ref VPC
  • AWS::ElasticLoadBalancingV2::TargetGroupでターゲットグループを作成する。
  • Targetプロパティで上記で作成したEC2インスタンスを登録する。
  # ------------------------------------------------------------#
  #  ALB Listner
  # ------------------------------------------------------------#
  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - TargetGroupArn: !Ref MyTG1
          Type: forward
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP
  • AWS::ElasticLoadBalancingV2::ListenerでALBのリスナーを作成する。
  • これによりALBが上記で作成したターゲットグループをListenするようになる。

RDS

  # ------------------------------------------------------------#
  #  Database Subnet Group
  # ------------------------------------------------------------#
  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties: 
      DBSubnetGroupDescription: My-SubnetGroup
      DBSubnetGroupName: My-SubnetGroup
      SubnetIds: 
        - !Ref PrivateSubnetA
        - !Ref PrivateSubnetC
      Tags: 
        - Key: Name
          Value: My-SubnetGroup

  • AWS::RDS::DBSubnetGroupでサブネットグループを作成する。
  • RDSにおいては、冗長性の観点から、複数のAZに存在するサブネットをグルーピングしたサブネットグループ内に作成しなければならないという決まりがある。

  # ------------------------------------------------------------#
  #  RDS Security Group
  # ------------------------------------------------------------#
  RDSSG1:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: RDS-SG-1
      GroupDescription: Allow Request from WebServer
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # http
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          SourceSecurityGroupId: !Ref WebSG1
      Tags: 
        - Key: Name
          Value: RDS-SG-1
  • ALB, EC2同様、RDSにアタッチするセキュリティグループを作成する。
  • TCPの3306番ポートをWebServerからのアクセスからのみ許可したいため、CidrIpではなくSourceSecurityGroupIdを設定する。

  # ------------------------------------------------------------#
  #  RDS 
  # ------------------------------------------------------------#
  Database:
    Type: AWS::RDS::DBInstance
    Properties: 
      AllocatedStorage: 20
      AllowMajorVersionUpgrade: false
      AutoMinorVersionUpgrade: false
      AvailabilityZone: ap-northeast-1a
      BackupRetentionPeriod: 0
      DBInstanceClass: db.t3.micro
      DBInstanceIdentifier: database-1
      DBName: !Ref DatabaseName
      DBSubnetGroupName: !Ref DBSubnetGroup
      DeleteAutomatedBackups: false
      DeletionProtection: false
      Engine: mysql
      EngineVersion: 8.0.20
      MasterUsername: !Ref DatabaseMasterName
      MasterUserPassword: !Ref DatabaseMasterPassword
      MaxAllocatedStorage: 1000
      MultiAZ: false
      PubliclyAccessible: false
      StorageEncrypted: false
      StorageType: gp2
      Tags: 
        - Key: Name
          Value: My-RDS-1
      VPCSecurityGroups: 
        - !Ref RDSSG1
  • AWS::RDS::DBInstanceで実際にDBインスタンスを作成する。
  • 基本的にはデフォルトのままで設定している。
  • 上記で作成したサブネットグループをDBSubnetGroupNameプロパティで指定している。
  • Parametersで設定していいるデータベース名、データベースマスターユーザー名、データベースマスターパスワードもそれぞれ、DBName, MasterUserName, MasterUserPasswordプロパティで指定している。
  • セキュリティグループはVPCSecurityGroupsプロパティで指定する。
    DBSecurityGroupsなるプロパティも存在するが、こちらはAWS::RDS::DBSecurityGroupで作成されたDBセキュリティグループなるものらしい。

DBセキュリティグループについては以下。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_WorkingWithSecurityGroups.html

VPC セキュリティグループ – EC2-VPC プラットフォーム用。
DB セキュリティグループ – EC2-Classic プラットフォーム用。

つまり、EC2インスタンスの項で記載したように、EC2-Classicなる昔の環境のものなので、DBセキュリティグループヲ使うことはほとんどなさそう。


まとめ

WordPressブログサイトをCloudFormationを使って構築した。
準備には時間がかかってしまうが、一度作ってしまえばすぐに環境構築ができるし、削除もスタックを削除するだけで完了する。

本記事を書くにも、「あ、あそこのキャプチャとりたいからまた環境作りたい!」ってなった時にすぐにテンプレートから起動できるのはとても助かった。

ただ、CloudFormationのデメリットとしては、AWSでしか利用できないことである。
次回は様々なサービスに対応しているTerraformなども触ってみたいと思う。

Discussion