0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【AWS】EC2(wordpress)+RDSの基本構成をCloudFormationで構築

Last updated at Posted at 2021-11-23

#■はじめに
EC2(wordpress)・RDSのシングル構成(※)を今度はCloudFormationで構築してみました。
AWSで基本的なブログサービスを構築する(シングル構成)

#■構成図
image.png

#■テンプレート概要

上記 85ページを参考に、
ネットワーク、セキュリティ、アプリケーションの3つに分ける。
加え、一部設定値を記述した外部ファイルの計4つを作成する。

  • ネットワーク ⇒ cf_network.yml
  • セキュリティ ⇒ cf_security.yml
  • アプリケーション ⇒ cf_application.yml
  • 設定ファイル ⇒ dev.cfg

#■テンプレート詳細

【ネットワークテンプレート】

VPC, サブネット, ルートテーブルについて記述する。

VPC
CidrBlockの指定。

サブネット
パブリックサブネット1,2、プライベートサブネット1,2のAZ,VPC,CidrBlockの指定。

DBサブネットグループ
SubnetIdsでプライベートサブネット1,2 であることを指定。

インターネットゲートウェイ
VPC1にアタッチすることを指定。

ルートテーブル
パブリックサブネット用のルートテーブルには localとインターネットゲートウェイ向けの設定。
プライベートサブネット用のルートテーブルには 宛先指定なし(localのみになる)の設定。

output
VPCID,サブネットID,サブネットグループ名、インターネットゲートウェイ名、ルートテーブルIDをアウトプット指定。

cf_network.yml
AWSTemplateFormatVersion: 2010-09-09
Resources: 
#-----------------------
#VPC Create
#-----------------------
  MyVPC1Cf:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.8.0/21
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: MyVPC1-Cf
#-----------------------
#Subnet Create
#-----------------------
#PublicSubnet1 create
  PublicSubnet1Cf:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      VpcId: !Ref MyVPC1Cf
      CidrBlock: 10.0.10.0/24
      Tags:
        - Key: Name
          Value: PublicSubnet1-Cf
#PublicSubnet2 create
  PublicSubnet2Cf:    
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1c"
      VpcId: !Ref MyVPC1Cf
      CidrBlock: 10.0.11.0/24
      Tags:
        - Key: Name
          Value: PublicSubnet2-Cf
#PrivateSubnet1 create
  PrivateSubnet1Cf:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      VpcId: !Ref MyVPC1Cf
      CidrBlock: 10.0.12.0/24
      Tags:
        - Key: Name
          Value: PrivateSubnet1-Cf
#PrivateSubnet2 create
  PrivateSubnet2Cf:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1c"
      VpcId: !Ref MyVPC1Cf
      CidrBlock: 10.0.13.0/24
      Tags:
        - Key: Name
          Value: PrivateSubnet2-Cf
#-----------------------
#RDS SubnetGroup Create
#-----------------------
  RdsSubnetGroupCf:
    Type: AWS::RDS::DBSubnetGroup
    Properties: 
      DBSubnetGroupName: RdsSubnetGroupCf
      DBSubnetGroupDescription: RdsSubnetGroupCf
      SubnetIds: 
        - !Ref PrivateSubnet1Cf
        - !Ref PrivateSubnet2Cf
      Tags: 
        - Key: Name
          Value: RdsSubnetGroup-Cf
#-----------------------
#InternetGateway Create
#-----------------------
  InternetGW1Cf:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: InternetGW1-Cf
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref MyVPC1Cf
      InternetGatewayId: !Ref InternetGW1Cf
#-----------------------
#Routetable Create
#-----------------------
#PublicRoutetable create
  PublicRoutetableCf:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref MyVPC1Cf
      Tags:
        - Key: Name
          Value: PublicRoutetable-Cf
  PublicRoutetableAssociationCf:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1Cf
      RouteTableId: !Ref PublicRoutetableCf
  PublicRouteCf:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRoutetableCf
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGW1Cf
#PrivateRoutetable create
  PrivateRoutetableCf:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref MyVPC1Cf
      Tags:
        - Key: Name
          Value: PrivateRoutetable-Cf
  PrivateRoutetableAssociationCf:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1Cf
      RouteTableId: !Ref PrivateRoutetableCf
Outputs:
#-----------------------
#VPC output
#-----------------------
    MyVPC1CfOutput:
      Value: !Ref MyVPC1Cf
      Export:
        Name: MyVPC1Cf-Id
#-----------------------
#Subnet output
#-----------------------
#PublicSubnet1Cf
    PublicSubnet1CfOutput:
      Value: !Ref PublicSubnet1Cf
      Export:
        Name: PublicSubnet1Cf-Id
#PublicSubnet2Cf
    PublicSubnet2CfOutput:
      Value: !Ref PublicSubnet2Cf
      Export:
        Name: PublicSubnet2Cf-Id
#PrivateSubnet1Cf
    PrivateSubnet1CfOutput:
      Value: !Ref PrivateSubnet1Cf
      Export:
        Name: PrivateSubnet1Cf-Id
#PrivateSubnet1Cf
    PrivateSubnet2CfOutput:
      Value: !Ref PrivateSubnet2Cf
      Export:
        Name: PrivateSubnet2Cf-Id
#-----------------------
#RDS SubnetGroup output
#-----------------------
    RdsSubnetGroupCfOutput:
      Value: !Ref RdsSubnetGroupCf
      Export:
        Name: RdsSubnetGroupCf-GroupName
#-----------------------
#InternetGateway output
#-----------------------
    InternetGW1CfOutput:
      Value: !Ref InternetGW1Cf
      Export:
        Name: InternetGW1Cf-Name
#-----------------------
#Routetable output
#-----------------------
#PublicRoutetableCf
    PublicRoutetableCfOutput:
      Value: !Ref PublicRoutetableCf
      Export:
        Name: PublicRoutetableCf-Id
#PrivateRoutetableCf
    PrivateRoutetableCfOutput:
      Value: !Ref PrivateRoutetableCf
      Export:
        Name: PrivateRoutetableCf-Id

【セキュリティテンプレート】

セキュリティグループについて記述する。

セキュリティグループ
EC2セキュリティグループとRDSセキュリティグループの作成。
EC2はsshとhttpのインバウンド、RDSはmysqlのインバウンド指定。

アウトプット
アプリケーションテンプレートから セキュリティグループのIDを参照するためGetAttで指定。

cf_security.yml
AWSTemplateFormatVersion: 2010-09-09
Resources: 
#-----------------------
#SecurityGroup Create
#-----------------------
#EC2 SecurityGroup create
  WebSg1Cf:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: WebSg1Cf
      GroupDescription: WebSg1Cf
      VpcId: !ImportValue MyVPC1Cf-Id
      SecurityGroupIngress:
#       ssh
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
#       http
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: WebSg1-Cf
#RDS SecurityGroup create
  RdsSg1Cf:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: RdsSg1Cf
      GroupDescription: RdsSg1cf
      VpcId: !ImportValue MyVPC1Cf-Id
      SecurityGroupIngress:
        - SourceSecurityGroupId: !Ref WebSg1Cf
          IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
      Tags:
        - Key: Name
          Value: RdsSg1-Cf
Outputs:
#-----------------------
#SecurityGroup output
#-----------------------
#WebSg1Cf
    WebSg1CfOutput:
      Value: !GetAtt WebSg1Cf.GroupId
      Export:
        Name: WebSg1Cf-Id
#RdsSg1Cf
    RdsSg1CfOutput:
      Value: !GetAtt RdsSg1Cf.GroupId
      Export:
        Name: RdsSg1Cf-Id
【アプリケーションテンプレート】

EC2, RDSについて記述する。

パラメータ
EC2インスタンスのイメージIDとインスタンスタイプの指定、キーペア名の指定、データベースパスワードの型定義。
イメージIDとは、マネジメントコンソールでいうと以下の部分に該当する。

image.png

CLIで以下を実行するとインスタンスイメージIDが取得できる。

$ aws ssm get-parameter --name /aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-x86_64-gp2 --query "Parameter.Value" --region ap-northeast-1

ami-0404778e217f54308

CloudFormationで自動で取得するにはParameterで以下を指定する。

  EC2ImageIdCf:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-x86_64-gp2

キーペアはあらかじめ作成しておく前提。
以下記述をしておくことで、マネジメントコンソールから選択できるようになる。
また、CLIからデプロイ実行時は"Default"のキーペア名が使用される

  KeyNameCf:
    Description: The EC2 Key Pair to allow SSH access to the instance
    Type: "AWS::EC2::KeyPair::KeyName"
    Default: "Mykeypair"

image.png

EC2
パブリックIPの自動割り当て有効化のため、"NetworkInterface:" を記述。
ここでインデックスを指定しないと自動割り当てされない。(もしくはVPC側の設定で自動割り当てされるようにする必要がある)
wordpressのインストールコマンドは「UserData」に記述。

NetworkInterfaceとは、マネジメントコンソールでいうと以下の部分に該当する。

image.png

テンプレートでは以下のように記述する。セキュリティグループID(GroupSet)も記述しなければならない。

      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !ImportValue PublicSubnet1Cf-Id
          GroupSet:
            - !ImportValue WebSg1Cf-Id

RDS
マスターユーザーパスワードは、コマンド実行時に外部ファイルをオーバーライド指定するので !Refで参照する

cf_application.yml
AWSTemplateFormatVersion: 2010-09-09
Parameters:
#-----------------------
#EC2 Instance Parameter
#-----------------------
  EC2ImageIdCf:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-x86_64-gp2
  EC2InstanceTypeCf:
    Type: String
    Default: t2.micro
#-----------------------
#EC2 Keypair Parameter
#-----------------------
  KeyNameCf:
    Description: The EC2 Key Pair to allow SSH access to the instance
    Type: "AWS::EC2::KeyPair::KeyName"
    Default: "Mykeypair"
#-----------------------
#RDS DatabasePassword
#-----------------------
  DatabasePassword:
    Type: String
    Description: Database password
    NoEcho: "true"
Resources:
#-----------------------
#EC2 Create
#-----------------------
  WebServer1Cf:
    Type: AWS::EC2::Instance
    Properties:
      KeyName: !Ref KeyNameCf
      ImageId: !Ref EC2ImageIdCf
      InstanceType: !Ref EC2InstanceTypeCf
      Monitoring: false
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !ImportValue PublicSubnet1Cf-Id
          GroupSet:
            - !ImportValue WebSg1Cf-Id
#wordpress install
      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
          cd /var/tmp
          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
      Tags:
        - Key: Name
          Value: WebServer1-Cf
#-----------------------
#RDS Create
#-----------------------
  Database1Cf:
    Type: AWS::RDS::DBInstance
    Properties:
      Engine: mysql
      EngineVersion: 5.7
      DBInstanceClass: db.t2.micro
      AllocatedStorage: 10
      StorageType: gp2
      MasterUsername: wordpress
      MasterUserPassword: !Ref DatabasePassword
      DBName: wordpress
      VPCSecurityGroups:
          - !ImportValue RdsSg1Cf-Id
      DBSubnetGroupName: !ImportValue RdsSubnetGroupCf-GroupName
      AvailabilityZone: "ap-northeast-1a"
      DBInstanceIdentifier: database-1-cf
      MultiAZ: false
      BackupRetentionPeriod: 0
      Tags:
        - Key: Name
          Value: Database1-Cf

【設定ファイル】

データベースパスワードのみ記述。

dev.cfg
DatabasePassword=xxxxxx

#■作成時に詰まった点

【ec2 「NetworkInterfaces」のエラー】

NetworkInterfacesの中にGroupSetを記述する必要があるが、
以下のようにNetworkInterfacesとGroupSetを同列に記述してエラーが発生していた。

      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !ImportValue PublicSubnet1Cf-Id
      GroupSet:
        - !ImportValue WebSg1Cf-Id

また、GroupSetではなく、SecurityGroupIds にIDを書くこともできるようだが、
そちらは私のテンプレートではエラーが出てしまっていた。List of Stringでないとか。
対処できていないがGroupSetで構築できてしまったので一旦パスした。

【外部ファイルからのデータベースパスワード読み込み不可】

エラー文字列をメモるのを忘れてしまったが、ファイル読み込み時に「パスワードに使用不可の文字が設定されている」といったようなエラー。
こちらも原因不明だが、外部ファイルを作り直したら読み込みに成功した(変な改行、ブランクが入っていた? 文字コードがおかしかった?)

#■deploy、deleteコマンド

作成時は依存性の低い順、削除時は逆順で以下実行。

【作成】

$ aws cloudformation deploy --template-file cf_network.yml --stack-name CFNetwork
$ aws cloudformation deploy --template-file cf_security.yml --stack-name CFSecurity
$ aws cloudformation deploy --template-file cf_application.yml --stack-name CFApplication --parameter-overrides $(cat dev.cfg)

【削除】

$ aws cloudformation delete-stack --stack-name CFApplication
$ aws cloudformation delete-stack --stack-name CFSecurity
$ aws cloudformation delete-stack --stack-name CFNetwork
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?