【AWS】CloudFormationでWebサービスを構築③（RDS編）

#1. はじめに
本投稿は以下の記事の続編となります。
[【AWS】CloudFormationでWebサービスを構築①（NW編）](https://qiita.com/chibiharu/items/ade872ce161f3577aea5)
[【AWS】CloudFormationでWebサービスを構築②（EC2編）](https://qiita.com/chibiharu/items/5d5fbc97f55ea6fa1e31)
本投稿を初めてご覧の方はまずはこちらの記事からお読みになって下さい。

#2. RDS編概要
今回の『【AWS】CloudFormationでWebサービスを構築③（RDS編）』では、Webサービスにおけるデータ管理を目的とするデータベース管理システム、Amazon RDSのテンプレートを作成します。
具体的なサービスとしては以下の通りとなります。

##2.1 「database.yml」で登場するサービス
- Amazon RDS
    - DBエンジン：MySQL
    - サブネットグループ
    - パラメータグループ
    - その他[詳細設定]

##2.2 RDS編構成図
RDS編で作成するテンプレート環境の構成図を下図の通りとします。
![chibiharu-cfn-qiita-web-env-target-rds.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570694/ecd9b82c-dd15-57ab-28f4-6d7f57455143.png)

#3. RDSテンプレートの作成
以下はRDS部分のテンプレートになります。
命名規則等、必要であればご自身の環境に合わせて修正してください。
修正が完了したら、作業用ディレクトリに「database.yml」というファイル名で保存してください。

```:database.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: Web2tier-database-Template


# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
### Project Prefix ###
  PJPrefix:
    Type: String
### RDS Name ###
  DBEngineName:
    Type: String
    Default: "web2tier-rds-mysql"
### RDS Database type & Major version ###
  MySQLMajorVersion:
    Type: String
    Default: "5.7"
    AllowedValues: [ "5.5", "5.6", "5.7" ]
### RDS Database type & Minor version ###
  MySQLMinorVersion:
    Type: String
    Default: "22"
### Instnce Options ###
  DBInstanceClass:
    Type: String
    Default: "db.m4.large" 
  DBEngineStorageSize:
    Type: String
    Default: "30"
  DBEngineStorageType:
    Type: String
    Default: "gp2"
### Database name ###
  DBName:
    Type: String
    Default: "testdb"
### User Options ###
  DBMasterUserName:
    Type: String
    Default: "dbuser"
    NoEcho: true
    MinLength: 1
    MaxLength: 16
    AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*"
    ConstraintDescription: "must begin with a letter and contain only alphanumeric characters."
  DBPassword: 
    Default: "DBPassword"
    NoEcho: true
    Type: String
    MinLength: 8
    MaxLength: 41
    AllowedPattern: "[a-zA-Z0-9]*"
    ConstraintDescription: "must contain only alphanumeric characters."
### AZ options ###
  MultiAZ: 
    Default: "false"
    Type: String
    AllowedValues: [ "true", "false" ]
    
    
### Resources ###
Resources: 
# ------------------------------------------------------------#
#  DB - Engine
# ------------------------------------------------------------#
  DBEngine: 
    Type: "AWS::RDS::DBInstance"
    Properties: 
      DBInstanceIdentifier: !Sub "${DBEngineName}"
      Engine: MySQL
      EngineVersion: !Sub "${MySQLMajorVersion}.${MySQLMinorVersion}"
      DBInstanceClass: !Ref DBInstanceClass
      AllocatedStorage: !Ref DBEngineStorageSize
      StorageType: !Ref DBEngineStorageType
      DBName: !Ref DBName
      MasterUsername: !Ref DBMasterUserName
      MasterUserPassword: !Ref DBPassword
      DBSubnetGroupName: !Ref DBSubnetGroup
      PubliclyAccessible: false
      MultiAZ: !Ref MultiAZ
      PreferredBackupWindow: "18:00-18:30"
      PreferredMaintenanceWindow: "sat:19:00-sat:19:30"
      AutoMinorVersionUpgrade: false
      DBParameterGroupName: !Ref DBParameterGroup  
      VPCSecurityGroups:
        - { "Fn::ImportValue": !Sub "${PJPrefix}-rds-sg" }
      CopyTagsToSnapshot: true
      BackupRetentionPeriod: 7
      Tags: 
        - Key: "Name"
          Value: !Ref DBEngineName
    DeletionPolicy: "Delete"
    
    
# ------------------------------------------------------------#
#  DB - SubnetGroup
# ------------------------------------------------------------#
  DBSubnetGroup: 
    Type: "AWS::RDS::DBSubnetGroup"
    Properties: 
      DBSubnetGroupName: !Sub "${DBEngineName}-subnet"
      DBSubnetGroupDescription: "-"
      SubnetIds: 
        - { "Fn::ImportValue": !Sub "${PJPrefix}-private-subnet-a" }
        - { "Fn::ImportValue": !Sub "${PJPrefix}-private-subnet-c" }
        
        
# ------------------------------------------------------------#
#  DB - ParameterGroup
# ------------------------------------------------------------#
  DBParameterGroup:
    Type: "AWS::RDS::DBParameterGroup"
    Properties:
      Family: !Sub "MySQL${MySQLMajorVersion}"
      Description: !Sub "${DBEngineName}-parm"
```

##3.1 RDSテンプレートのビルド
作成したCFnテンプレートのビルドを行います。

以下コマンドを実行してください。
※ スタック名やプレフィックス、また追加で指定したいパラメータ等があればご自身の環境に合わせ修正して下さい。

```:RDSテンプレートのビルドコマンド
$ aws cloudformation create-stack \
--stack-name web2tier-RDS-stack \
--template-body file://./databse.yml \
--parameters ParameterKey=PJPrefix,ParameterValue=web2tier
```

↓ 構文エラーが無ければ、以下のような結果が出力されます。

```:実行結果
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxx:stack/<スタックネーム>/<メタ番号>"
}
```

##3.2 SSMを使用したApacheとMySQL(RDS)の連携
ここまでの手順でWebサービスとしての基盤環境は全て構築できました。
後は、最後の完了要件である「RDSで作成したDBレコードのブラウザ閲覧」を達成する為に、ApacheとRDSの連携作業を行います。

作業は以下の流れで行います。
① SSMでWebサーバへ接続
② Webサーバを踏み台にMySQL(RDS)へ接続
③ テストレコードの作成
④ WebサーバにてMySQLとの連携設定

では早速作業を行っていきます。

###3.2.1 SSMにセッションマネージャーでWebサーバへ接続
Amazon Systems Managerの「セッションマネージャー」という機能を使用して、Webサーバへ接続し、コンソール作業を行えるようにします。
※接続先のWebサーバはAZ-a,cのどちらでも構いません

詳細な手順については省かせていただきますが、Google等で「AWS SSM EC2 接続」とかで検索をかけると手順が載っている記事が沢山でてきますので、そちらを参照していただければと思います。

###3.2.2 MySQLへ接続
Webサーバを踏み台に、MySQLへ接続します。

セッションマネージャーでWebサーバへ繋いでいる状態だと思いますので、コンソール上にて以下手順を実行してください。

```
# DB操作の為のMySQLをインストール
$ sudo yum -y install mysql

# WebサーバーのMySQLクライアントからRDSに接続
# ※下記コマンド実行後、パスワードを聞かれますので、RDS作成時に設定したパスワードを入力してください
$ mysql -h <RDSのエンドポイント> -P 3306 -u <ユーザー名> -p
```

↓ 接続後、プロンプトが以下のようになっていればMySQLへの接続は完了です

```
mysql [{none}]> 
```

###3.2.3 テストレコードの作成
MySQL上にて、ブラウザに表示させる為の、テストレコードを作成します。
以下手順を実行してください。

```
# テスト用のデータベースの作成
mysql [{none}]> create database testdb;

# テーブルの作成（テーブル名：user）
mysql [{none}]> create table testdb.user(id int , country varchar(20));

# 作成したテーブルにデータを挿入
mysql [{none}]> INSERT INTO testdb.user
  (id, country)
VALUES 
  (1, 'Japan'),
  (2, 'Argentina'),
  (3, 'Italy'),
  (4, 'India'),
  (5, 'Australia'),
  (6, 'Czech'),
  (7, 'Portugal'),
  (8, 'Mongolia'),
  (9, 'Germany'),
  (10, 'Belgium');

# データが登録できたことを確認する
mysql [{none}]> select * from testdb.user;

# MySQLから抜ける
mysql [{none}]> quit
```

###3.2.4 Webサーバにて、PHPとMySQLの連携設定
先程作成したテストレコードをWebサーバのブラウザで表示させる為の設定を行います。
PHPを新規インストールし、MySQLと連携するよう設定ファイルを修正します。

同じく、コマンドライン上にて以下手順を実行してください。
<b>注意事項：</b>また、本手順は両Webサーバ(ZA-a, AZ-c)にて、実施してください。

① WebサーバにPHPとMySQLを扱うためのモジュールをインストールする

```
$ sudo yum -y install php php-mysql
```
② 拡張子が.phpのファイルがphpファイルとして読み込まれるように設定する

vimエディタで「httpd.conf」を開きます

```
$ sudo vim /etc/httpd/conf/httpd.conf
```

"IfModule mime_module"というタグで囲まれているセクション内に、以下コードを追加します。
コード：AddType application/x-httpd-php .php

```:httpd.conf-編集前
<IfModule mime_module>
～～ 略 ～～
</IfModule>
```

↓ セクション内の末尾あたりにコード：AddType application/x-httpd-php .phpを追記

```:httpd.conf-編集後
<IfModule mime_module>
～～ 略 ～～
AddType application/x-httpd-php .php
</IfModule>
```

その後、Apacheを再起動し、設定ファイルを再読み込みさせます。
以下コマンドを実行して下さい。

```
$ sudo systemctl restart httpd
```

③ PHPがApacheに読み込まれているか確認
PHPのバージョン情報をindex.phpに追記を実行し、ブラウザでそのバージョン情報が閲覧できるかを確認します。

以下コマンドを実行して下さい。

```
$  sudo sh -c "echo '<?php phpinfo(); ?>' >> /var/www/html/index.php"
```

ブラウザにて、以下のURLで検索をかけます。
URL：www.<ドメイン名>/index.php

以下のような画面が表示されれば無事PHPは読み込まれています。
![QiitaWebPHP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570694/4654d776-c8ee-dc4c-e2e2-fe56ce5c57b9.png)


④ index.phpをDB情報を参照させるコードに修正する
先程は、PHPのバージョン情報を表示させるコードをindex.phpに追記しましたが、今度はRDSにて作成しらDBレコードを参照させるコードを記載します。

vimエディタでindex.phpファイルを起動します。

```
$ sudo vim /var/www/html/index.php
```

下記のコードをindex.phpに貼り付けて下さい。
その際、<>で囲まれた以下の箇所を修正して下さい。
・<RDSのエンドポイント>
・<ユーザー名>
・<パスワード>

```php
<?php
try
{
$dbs = "mysql:host=<RDSのエンドポイント>;dbname=testdb;charset=utf8";
$user='<ユーザー名>';
$password='<パスワード>';
$dbh=new PDO($dbs, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$sql='SELECT * FROM user';
$stmt=$dbh->prepare($sql);

$dbh=null;
//実行
$stmt->execute();

$all = $stmt->fetchAll();
//配列を表示
foreach($all as $loop){
  echo $loop['id']." ".$loop['country'].'<br>';
}

}
catch (Exception $e)
{
        print '接続失敗';
        exit();
}
?>
```

先程と同じようにApacheを再起動し、設定ファイルを再読み込みさせます。
以下コマンドを実行して下さい。

```
$ sudo systemctl restart httpd
```

#4. 動作確認 - RDSで作成したDBレコードのブラウザ閲覧
では、最後に残った完了要件【RDSで作成したDBレコードのブラウザ閲覧】の動作確認を行います。
ブラウザにて、以下のURLで検索をかけます。
URL：www.<ドメイン名>/index.php

RDSにて作成したDBテーブルが表示されていることを確認します。
![qiitawebcfnsuccess.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570694/ddd18c5b-a5f7-cd65-a312-74e5bad0c9af.png)


#5. まとめ
以上で、本記事は全て終了になります。
CFnと最低限の手作業でこうも簡単にWebサーバの作成が完了しました。

また、本記事で公開しているCFnコードは最低限のコードしか記載しておりません。
ここでは紹介していない組み込み関数や構文がCFnにはまだまだ沢山あります。

是非、本記事がCFnに関しての興味を持ってもらえる良い機会になればと思っています。

--- 記事一覧 ---
[①【AWS】CloudFormationでWebサービスを構築①（NW編)](https://qiita.com/chibiharu/items/ade872ce161f3577aea5)
[②【AWS】CloudFormationでWebサービスを構築②（EC2編)](https://qiita.com/chibiharu/items/5d5fbc97f55ea6fa1e31)
[③【AWS】CloudFormationでWebサービスを構築③（RDS編)](https://qiita.com/chibiharu/items/dc42c6a7ac9cb6740bce)