[チュートリアル]AWSにEC2,RDS,S3の環境を作ってWEBアプリケーションを動かす

#0. はじめに

「AWSの基礎を理解したいのですがどうしたらいいでしょう？」と知人に聞かれて、「こんなことやってみたらいいんじゃないでしょうか！」と提案したものの、自分ではやったことなかったのをきっかけに作り始めたチュートリアルです。

WEBサービスもサーバレスになっていく時代の流れもありますが、このチュートリアルではAWSを勉強し始めたら最初に出てくるEC2(サーバー)とRDS(データベース)とS3(ストレージ)を使ってWEBアプリケーションを作ることを通して、AWSの基礎を理解することを目的にしています。

筆者も何度も環境を作ったり壊したりするうちに、自然とAWSの理解が進みました。このチュートリアルが、みなさんのAWSの理解の一助になれば幸いです。

また、初心者が書いたチュートリアルですので、抜け落ちや間違い等ありましたらご指摘いただけたらと思います。よろしくお願いいたします。


##自己紹介

* WEBエンジニア(インフラは未経験)
* 2年前にAWSのSAA(ソリューションアーキテクトアソシエイト)という設計の資格は取得したものの、その後AWSにまったく触れてこなかった人
* 2019年12月の資格取得の記事　→　[【初心者向け】3週間でAWS認定ソリューションアーキテクトアソシエイトに合格する勉強法(2019.12)](https://qiita.com/torabo/items/a93a7066b41558d4d7e7)

##このチュートリアルの対象者と前提知識

* EC2は起動したことはある程度で、RDSやS3も使ってネットワークを構成してアプリを動かしてみたい方
* PHPで作った簡単なアプリ(ここでは画像アップロード付き掲示板を例とします)のソースコードがあると動作確認ができます
* AWSアカウントがあることが前提で、基本無料枠の中で作っていきますが、EC2やRDSは使わないときは停止しておいてください
* AWSについての基礎的な知識や、AWSアカウントを作成したあとに設定しておくと良いことなどは以下のサイトを参考にしてください
* AWS初心者の方の参考サイト　→　[基本的なシステム構成図を理解するためのAWS基礎をまとめてみた](https://qiita.com/g_ayushi/items/0e0f34d19813b8fdc2b8)　
* AWSのアカウントを作ったら　→　[AWSアカウントを取得したら速攻でやっておくべき初期設定まとめ](https://qiita.com/tmknom/items/303db2d1d928db720888)


##ネットワーク構成とチュートリアルのゴール
![aws_board.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192627/d9fe33ad-9c44-52dd-4ed0-074339f7ebe6.png)


* リージョンは、アジアパシフィック(東京) ap-northeast-1を使う
* VPCを作成し、その中にパブリックサブネット1つ、プライベートサブネット2つを作成する
* パブリックサブネットにEC2(サーバー)を作成し、その中にLAMP環境(Linux,Apache,MySQL,PHP)を作成する
* VPCにインターネットゲートウェイをアタッチし、EC2とインターネットとの通信を行う
* プライベートサブネットにRDS(データベース)を作り、EC2と通信できるようにする
* リージョンにS3を、VPCにエンドポイントを作成し、エンドポイントを使ってS3(画像用ストレージ)とEC2が通信できるようにする
* RDSやS3はパブリックアクセスをブロックして、EC2からしかアクセスできないようにする
* EC2でPHPのアプリを動かして、RDSとデータをやり取りしたり、S3に画像ファイルを保存したりするのをゴールとします


##このチュートリアルでやらないこと

* Elastic IP(固定IPアドレス)の使用と独自ドメインのDNS設定
* ロードバランサーによる負荷分散 (EC2を複数台作成してトラフィックを分散する)
* オートスケーリング (負荷に応じてEC2の台数を増減させる)
* データベースのレプリケーション (データベースの複製を作成する)




##AWSリソースの命名規則
* このチュートリアルでは、AWSリソース(EC2やRDSなど)の名前の付け方は、次のサイトの命名規則を参考にしています
* 参考にさせていただいた記事　→ [弊社で使っているAWSリソースの命名規則を紹介します](https://dev.classmethod.jp/articles/aws-name-rule/)　
* 環境構築の例としてPHPの掲示板アプリをEC2に作るのを想定して、システム名はboard、環境は開発でdevとしています
* 例えば、VPCのIDは「board-dev-vpc」、EC2のNameは「board-dev-app01」のように命名することにします

#目次
[0. はじめに](#0-はじめに)
[1. VPC](#1-vpc)
[2. EC2](#2-ec2)
[3. RDS](#3-rds)
[4. S3](#4-s3)
[5. おわりに](#5-おわりに)

#1. VPC

* VPCとは、Virtual Private Cloudの略で、AWS上に作成できるプライベート仮想ネットワーク空間です
* VPC = お弁当を作るときのお弁当箱のイメージ
* サブネット = お弁当箱を仕切りで分けたそれぞれの部分で、そこにおかず(EC2などのAWSリソース)を詰めるイメージです
* 以下IPアドレス、CIDR(サイダー)などの用語が出てきますが、詳しく学びたい方は次を参考にしてください　→　[IPアドレスの基礎知識](https://qiita.com/mogulla3/items/efb4c9328d82d24d98e6)


##1-1.VPCの作成

AWSマネジメントコンソール→VPC→左のメニューのVPC→`VPCを作成`

**VPCの設定**
　名前タグ : `board-dev-vpc`
　IPv4 CIDR ブロック : `10.0.0.0/16`
　IPv6 CIDR ブロック : `IPv6 CIDR ブロックなし`にチェック
　テナンシー : `デフォルト`

`VPCを作成`をクリックし、VCPが作成できたことを確認します

##1-2.サブネットの作成

* パブリックサブネット1つ、プライベートサブネットを2つ作成します
* パブリックサブネットは、インターネット経由で直接通信できるサブネット
* インターネット経由で直接通信できないサブネットが、プライベートサブネットです
* パブリックかプライベートかは、インターネットとつなげる設定（インタネットゲートウェイをアタッチ）をするかしないかで変わります
* プライベートサブネットをアベイラビリティゾーンを分けて2つ作る理由は、RDS(データベース)作成に必要なためです

VPCの左のメニュー→サブネット→`サブネットを作成`

**VPC**
　VPC ID : `board-dev-vpc(1-1で作成したVPC)`を選択

**サブネットの設定**
**①パブリックサブネット**
　サブネット名 : `board-dev-public-subnet01`
　アベイラビリティーゾーン : `ap-northeast-1a`を選択
　IPv4 CIDR ブロック : `10.0.0.0/24`

新しいサブネットを追加をクリックして、同じ様に次の②を入力します

**②プライベートサブネット1**
　サブネット名 : `board-dev-private-subnet01`
　アベイラビリティーゾーン : `ap-northeast-1a`を選択
　IPv4 CIDR ブロック : `10.0.1.0/24`

新しいサブネットを追加をクリックして、同じ様に次の③を入力します

**③プライベートサブネット2** <font color='red'>(アベイラビリティゾーンが①や②と違うので注意）</font>
　サブネット名 : `board-dev-private-subnet02`
　アベイラビリティーゾーン : `ap-northeast-1c`を選択
　IPv4 CIDR ブロック : `10.0.2.0/24`

`サブネットの作成`をクリックし、3つのサブネットが作成できたことを確認します


##1-3.ルートテーブルの作成

* ルートテーブルとは、サブネット内にあるEC2などのインスタンスが、どこに通信にいくかの経路(ルート)をまとめたものです
* まずルートテーブルだけ作っておいて、サブネットに取り付けておきます（アタッチしておく）
* あとからルートの設定をします（1-5.パブリックサブネットのルートテーブルの設定)

VPCの左のメニュー→ルートテーブル→`ルートテーブルを作成`

　名前 : `board-dev-public-rtb`
　VPC : `board-dev-vpc(1-1で作成したVPC)`を選択

`ルートテーブルを作成`をクリックし、作成できたことを確認します。

作成したルートテーブルの右上のアクションから、`サブネットの関連付けを編集`をクリックします
`パブリックサブネット(board-dev-public-subnet01)`を選択
`関連付けを保存`をクリックしてアタッチします


##1-4.インターネットゲートウェイの作成とVPCへのアタッチ

* インターネットとの通信口(インターネットゲートウェイ)を作って、それをVPCに取り付ける(アタッチする)ことで、VPCからインターネットにつながるようになります

VPCの左のメニュー→インターネットゲートウェイ→`インターネットゲートウェイの作成`
名前 : `board-dev-igw`
`インターネットゲートウェイの作成`をクリックし、作成できたことを確認します。

作成したインターネットゲートウェイの右上のアクションから、`VPCにアタッチ`をクリックします
VPC : `board-dev-vpc(1-1で作成したVPC)`を選択
`インターネットゲートウェイのアタッチ`をクリックして、VPCにインターネットゲートウェイをアタッチします

##1-5.パブリックサブネットのルートテーブルの設定

* パブリックサブネットのルートテーブルに以下の設定をすることで、パブリックサブネット内のEC2からの通信はインターネットゲートウェイがその宛先になります
* デフォルトゲートウェイとは、宛先が分からない通信はすべてそこに送られる出入口です

VPCの左のメニュー→ルートテーブル→`board-dev-public-rtb（パブリックサブネットにアタッチされているルートテーブル)`にチェック
下の`ルート`のタブの中の`ルートを編集`をクリック
`ルートを追加`をクリックして以下を入力

送信先 : `0.0.0.0/0` (デフォルトゲートウェイ）
ターゲット : `インターネットゲートウェイ`を選択してから`1-4で作成したイboard-dev-igw`を選択

`変更を保存`をクリックして、保存します

##1-6.VPCのまとめ

* VPCは仮想ネットワーク空間で、その中にパブリックサブネット1つとプライベートサブネット2つを作成しました
* パブリックサブネットだけインターネットと通信できる(この中にEC2を配置予定)
* RDS(データベース)を配置する予定のプライベートサブネットは、直接インターネットと通信できないようにしておく(セキュリティ向上ため)
* ここまででネットワークの枠組みができましたので、以降でEC2やRDSなどのAWSリソースを配置していきます


#2. EC2

* EC2は、Elastic Compute Cloudの略で、ECCなのでEC2(イーシーツー)です
* EC2＝サーバーだと思ってて良いと思います
* VPCに作ったパブリックサブネットの中にEC2という仮想サーバーを作っていきます
* 参考 →　[AWS EC2でWebサーバーを構築してみる](https://qiita.com/arashida/items/629aaed33401b8f2265c)

##2-1.EC2を作成する

AWSマネジメントコンソール→EC2→左のメニューのインスタンス→`インスタンスを起動`

**ステップ 1: Amazon マシンイメージ (AMI)**
　無料枠の対象の、`Amazon Linux 2 AMI (HVM), SSD Volume Type(64 ビット (x86))`　を選択

**ステップ 2: インスタンスタイプの選択**
　無料枠の対象の、`ファミリーt2、タイプt2.micro` を選択して、`次のステップ:インスタンスの詳細の設定`をクリック

**ステップ 3: インスタンスの詳細の設定**
　以下の3つの部分だけ、以下の通りに設定してください（その他についはデフォルトのまま）
　　ネットワーク : `board-dev-vpc(1-1で作成したVPC)`
　　サブネット : `board-dev-public-subnet01(1-2で作成したパブリックサブネット)`　<font color='red'>※publicと付いてるもの</font>
　　自動割り当てパブリック IP : `有効`　<font color='red'>※有効にしないとパブリックIPが付与されない</font>
　`次のステップ:ストレージの追加`をクリック

**ステップ 4: ストレージの追加**
　サイズ(8GiB)やボリュームタイプ(汎用SSD(gp2))などデフォルトのままで、`次のステップ:タグの追加`をクリック

* ここではEBS(Elastic Block Strage)の設定をしています
* EBSはEC2用のストレージと考えておいて良いかなと思います

**ステップ 5: タグの追加**
　タグの追加を押して、キー　: `Name`、値 : `board-dev-app01` を入力して、`次のステップ:セキュリティグループの設定`をクリック

**ステップ 6: セキュリティグループの設定**

* セキュリティグループとは、EC2単位の通信許可の設定のことです（EC2単位というところがポイントです）

　セキュリティグループの割り当て : `新しいセキュリティグループを作成する`を選択
　セキュリティグループ名 : `board-dev-app-sg`
　説明 : `board-dev-app-sg`
　ルールの追加を押して、`SSH`と`HTTP`と`HTTPS`の３つを追加し、ソースは`カスタム0.0.0.0/0`にする(以下参照)
![スクリーンショット 2021-10-28 0.47.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192627/6745ee67-3902-4e22-b1a3-17a69c1b4734.png)

* 0.0.0.0/0は、すべてのIPアドレスからEC２にアクセスできることを許可する設定
* デフォルトでは、0.0.0.0/0, ::/0と表示されていますが、::/0はIPv6の設定なので省略しても大丈夫です

　設定できたら、`確認と作成`をクリック

**ステップ 7: インスタンス作成の確認**
　設定を確認して、`起動`をクリック
　次にキーペアについての画面が出ますが、キーペアがない場合について説明します

 `新しいキーペアの作成`を選択
　キーペアのタイプ : `RSA`を選択
　キーペア名 : `board-dev-app-key` （例としてここではこの名前にします)
`キーペアのダウンロード`をクリックして、作ったキーペアをダウンロードします

`インスタンスの作成`をクリックすると、インスタンスの作成が始まり、しばらくたつとEC2インスタンスが起動します


##2-2.EC2へのSSH接続

* 作成したインスタンスのインスタンスIDをクリック→接続→SSHクライアントに、接続方法が書かれています
* 例として、~/download/に2-1のステップ7で作成したキーペアが保存されている場合の手順は以下です(Macの場合）

**1.ターミナルを開いて、キーを~/.ssh/に移動します**

```bash
　$ mv ~/downloads/board-dev-app-key.pem ~/.ssh/
```
**2.キーの権限を変更します**

```bash
　$ chmod 400 ~/.ssh/board-dev-app-key.pem
```

**3.SSH接続します**

```bash
　$ ssh -i ~/.ssh/board-dev-app-key.pem ec2-user@IPADDRESS
```

* IPADDRESSの部分は、`インスタンスのパブリックIPv4アドレス`を指定してください(以下参照、<font color='red'>このIPアドレスはEC2を起動するたびに変化するので注意してください</font>）

![aws_ec2_ip2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192627/7421471a-faaa-44ff-cc25-c69015262ef4.png)


* インスタンスのパブリックIPv4アドレスを固定するには、ElasticIPというものを使いますがこのチュートリアルでは扱いません
* iオプションは秘密鍵を使うということ(identityファイル)
* 初回接続時は、Are you sure you want to continue connecting (yes/no)?と聞かれるのでyesと入力
* こんな画面が表示されたら接続できています（分かりにくいですが、EC2と書いてあります）

　　![スクリーンショット 2021-10-28 22.56.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192627/d83467d7-69db-1ec9-c719-9c478160b778.png)

* 手元のPCから、1-4で作ったインターネットゲートウェイを通ってEC2に接続しています
* 2-1でEC2を作成するときに、ステップ6で`SSH`での接続を許可したのでSSHコマンドでEC2に接続できた、のもポイントです


##2-3.ApacheとPHPをインストール

* 以下の公式のチュートリアルのステップ2までを進めます（手順は以下です）
* 参考　→　[Amazon Linux 2 に LAMP ウェブサーバーをインストールする](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html)

**1.ソフトウェアの更新**

```bash
$ sudo yum update -y
```

**2.PHPをインストール**

```bash
$ sudo amazon-linux-extras install -y php7.2

インストールされたか確認
$ php -v
PHP 7.2.34 (cli) (built: Oct 21 2020 18:03:20) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
```
**3.Apacheをインストール**

```bash
$ sudo yum install -y httpd
```

**4.Apacheを起動**

```bash
$ sudo systemctl start httpd
```

**5.systemctl コマンドを使用して、EC2インスタンスが起動するたびに Apacheが起動するように設定**

```bash
$ sudo systemctl enable httpd

次のコマンドで、enabledとなっていることを確認
$ sudo systemctl is-enabled httpd
```

**6.IPアドレスをブラウザで叩くとApacheの画面が表示されるのを確認する**

* ブラウザで、http://IPADDRESS/ と入力して、以下のApacheの画面が表示されればOK
* IPADDRESSは、`EC2インスタンスのパブリックIPv4アドレス`
* 2-1でEC2を作成するときに、ステップ6で`HTTP`での接続を許可したので、http://IPADDRESS/ でEC2に接続できたのがポイントです

![aws_apache.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192627/74354bca-7e2f-8e7a-2a4b-ed6dc9de47e1.png)

**7./var/www/html の所有者とグループがrootになっているので、ec2-userに書き込み権限を割り当てる**

①　ec2-user を apache グループに追加

```bash
$ sudo usermod -a -G apache ec2-user
```
②　一度ログアウトし、再度ログインして新しいグループapacheができているのを確認

```bash
$ exit
$ ssh -i ~/.ssh/board-dev-app-key.pem ec2-user@IPADDRESS
$ groups
ec2-user adm wheel apache systemd-journal
```

③/var/www とそのコンテンツのグループ所有権を apache グループに変更

```bash
$ sudo chown -R ec2-user:apache /var/www
```

**8.LAMP サーバーをテスト（phpinfoを表示）**

①　phpinfo.phpを作成

```bash
$ echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php
```
② ブラウザで、http://IPADDRESS/phpinfo.php と入力して、以下のphpinfoが表示されるのを確認
![スクリーンショット 2021-11-01 11.16.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192627/dac48a73-36f0-ce11-5c0c-a536508b4e1d.png)

③　確認できたら、phpinfo.php ファイルを削除しておく

```bash
$ rm /var/www/html/phpinfo.php
```

##2-4.EC2のまとめ

* EC2は仮想サーバー
* EC2へSSH接続できたり、ブラウザでApacheやphpinfoの画面が表示できたりしたのは、2-1のセキュリティグループでその設定をしたため
* EC2を使わないときは、コンソール画面の`インスタンスの状態`から`インスタンスを停止`をクリックして停止しておきましょう
* 停止中に`インスタンスを開始`をクリックするとEC2が起動しますが、起動するたびにパブリックIpv4アドレスは変わるので注意してください
* ちなみに、起動中に再起動する場合には、パブリックIPv4アドレスは変わりません
* EC2を削除する場合は、`インスタンスの状態`から`インスタンスを終了`をクリックしてください



#3. RDS

* RDSは、Relational Database Serviceの略、つまりリレーショナルデータベースです
* RDBMS(Relational DataBase Management System)として、MySQLをいれて使います

##3-1.EC2にDB用のセキュリティグループを作成

* セキュリティグループとは、EC2単位の通信許可設定のこと
* セキュリティグループの設定で、RDSへのアクセスはEC2からのみに制限します

EC2→左のメニューのセキュリティグループ→`セキュリティグループを作成`

　セキュリティグループ名 : `board-dev-db-sg`
　説明 : `board-dev-db-sg`
　VPC : `board-dev-vpc(1-1で作成したVPC）`　（一度☓を押してデフォルトVPCとを削除すると選べるようになります）
　インバウンドルール
　　`ルールを追加する`をクリックして入力欄を表示する
　　タイプ : `MYSQL/Aurora`、ソースは`カスタム EC2のセキュリティグループ(board-dev-app-sg)`
　アウトバウンドルールはデフォルトのまま（DBから外に出る通信許可設定で、0.0.0.0/0はすべて許可の意味）

`セキュリティグループを作成`をクリックして、セキュリティグループを作成

##3-2.DB用のサブネットグループの作成

* RDSを作成するために、複数のサブネットをまとめたサブネットグループが必要なので作成します
* サブネットグループを作成するためには、アベイラビリティゾーンが別のサブネットを2つ用意しておきます（1-2で２つ作成済み)

AWSマネジメントコンソール→RDS→左のメニューのサブネットグループ→`DBサブネットグループを作成`

　名前 : `board-dev-private-subnet-g`
　説明 : `board-dev-private-subnet-g`
　VPC : `board-dev-vpc(1-1で作成したVPC)`
　アベイラビリティーゾーン : `ap-northeast-1a` と `ap-northeast-1c`にチェック
　サブネット : `subnet (10.0.1.0/24)` と `subnet (10.0.2.0/24)`にチェック

`作成`をクリックして、サブネットグループを作成

##3-3.RDSを作成

* データベースそのものを作成していきます

RDS→左のメニューのデータベース→`データベースの作成`

　データベース作成方法 : `標準作成`
　エンジンのタイプ : `MySQL`
　テンプレート : `無料利用枠`
　DB インスタンス識別子 : `board-dev-rds`
　マスターユーザー名 : `admin`
　マスターパスワード : `rdsadmin`
　DB インスタンスクラス : `db.t2.micro`
　ストレージタイプ : `汎用SSD(gp2)`
　ストレージ割り当て : `20`GiB
　ストレージの自動スケーリングを有効にする : `チェックを外す`　(必要ないと思われるため無効にしています)
　Virtual Private Cloud (VPC) : `board-dev-vpc(1-1で作成したVPC）`
　サブネットグループ : `board-dev-private-subnet-g(3-2で作成したサブネットグループ)`
　パブリックアクセス : `なし`（EC2からしかアクセスできないようにするため）
　VPC セキュリティグループ : `既存の選択`
　既存のVPC セキュリティグループ : `board-dev-db-sg(3-1で作成したセキュリティグループ)` (☓を押してdefaultを消してから選択)
　アベイラビリティーゾーン : `ap-northeast-1a`
　追加設定のデータベースポート : `3306`(デフォルト）
　データベース認証オプション : `パスワード認証`

`データベースの作成`をクリックすると、データベースの作成が始まるのでしばらく待って起動を確認します

##3-4.EC2とRDSを接続する

* EC2からRDSへ接続するために、RDSのエンドポイントの情報が必要になります
* エンドポイントは、起動したRDSの`接続とセキュリティタブ`→`エンドポイントとポート`の中に書かれています

![aws_rds_endpoint2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192627/e9940840-e50f-9bdc-083c-6d872092daf0.png)



**1.EC2にMySQLをインストール**

```bash
$ sudo yum install mysql -y
```

**2.RDSへ接続**

```bash
$ mysql -h RDSのエンドポイント -u admin -p
Enter password : rdsadmin を入力

以下表示さればRDSと接続できています
MySQL [(none)]> 

切断
MySQL [(none)]> exit　
```

##3-5.EC2にphpMyAdminを導入

* phpMyAdminを使ってデータベースを操作したい場合はこの手順に沿って導入してください
* 参考　→　[公式チュートリアル:Amazon Linux 2 に LAMP ウェブサーバーをインストールするのステップ4](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html)

**1.EC2にphpMyAdminをダウンロードして展開**

```bash
$ cd /var/www/html
$ sudo wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.tar.gz
$ sudo mkdir phpMyAdmin
$ sudo tar -xvzf phpMyAdmin-latest-all-languages.tar.gz -C phpMyAdmin --strip-components 1
$ sudo rm phpMyAdmin-latest-all-languages.tar.gz
```

**2.必要な依存ファイルをインストール**

```bash
$ sudo yum install php-mbstring php-xml -y
```

**3.設定ファイルの更新**

```bash
$ cd /var/www/html/phpMyAdmin
$ sudo cp config.sample.inc.php config.inc.php
$ sudo vim config.inc.php

30行目の'localhost'の部分を以下のとおり修正
修正前
$cfg['Servers'][$i]['host'] = 'localhost'
修正後
$cfg['Servers'][$i]['host'] = 'RDSのエンドポイント'
```

**4.apacheとphp-fpmを再起動**

```bash
$ sudo systemctl restart httpd
$ sudo systemctl restart php-fpm
```

**5.phpMyAdminへアクセス**

* ブラウザに、http://IPADDRESS/phpMyAdmin/ を入力してアクセス
* IPADDRESSは、`インスタンスのパブリックIPv4アドレス`
* 以下のphpMyAdminのログイン画面が表示されたら、3-3で作成した`マスターユーザ名(admin)`と`パスワード(rdsadmin)`でログイン

![aws_phpMyAdmin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192627/2bbdba4a-d5ca-37d6-a083-5316bb581cec.png)

##3-6.PHPアプリからRDSへ接続

* gitなどを使って、お手持ちのPHPアプリのソースを/var/www/html/以下の任意のディレクトリにクローンしてください
* 例えば、/var/www/html/board/index.php　には、http://IPADDRESS/board/index.php でアクセスできます
* RDSへの接続設定の例は以下です

```php
$dsn = 'mysql:host=RDSのエンドポイント; dbname=board';
$user = 'admin';
$password = 'rdsadmin';
```
* 接続がうまくできていれば、EC2にデプロイしたアプリからRDSへデータの参照や更新ができるはずです

##3-6.RDSのまとめ

* RDSはリレーショナルデータベース
* RDSはインターネットと直接通信しないプライベートサブネットに配置して、アクセスはEC2からのみに制限しパブリックアクセスはさせない
* RDSを使わないときは、コンソール画面の`アクション`から`停止`をクリックして停止しておきましょう
* 停止状態から`開始`をクリックするとRDSが起動します
* 再起動しても、接続に必要なエンドポイントは変わりません
* `削除`をクリックするとデータごとデータベースが削除されます
* アベイラビリティゾーンが別のサブネットが2つ必要な理由は、2つ目のサブネットにRDSの複製(レプリカ)を配置して高可用性や耐障害性を実現するのが前提になっているためだと思われます(このチュートリアルではレプリカは作成しませんでした)


#4. S3

* S3は、Simple Storage Serviceの略で、SSSなのでS3(エススリー)です
* google drive や drop boxのような、様々なファイルを保存できるオンラインストレージのこと
* 今回は、画像ファイルを保存したり、読み込んだりするのに使用します
* 参考　→　[S3まとめ](https://qiita.com/iron-breaker/items/f35c1d54887c434a321a)

##4-1.S3のバケットを作成

* バケットとは、S3のアイコンのとおりファイルを入れるバケツのことです

AWSマネジメントコンソール→S3→左のメニューのバケット→バケットを作成

　バケット名 : `board-dev-contents-XXXXXXXXXXXX`　
　 <font color=red>※　S3のリソースはAWS全体で一意にする必要があるため、XXXXXXXXXXXXの部分は12桁のAWSのアカウント番号を例として使用しています</font>
　AWSリージョン : `ap-northeast-1`
　このバケットのブロックパブリックアクセス設定 : `パブリックアクセスをすべてブロック`にチェック
　バケットのバージョニング : `無効にする`　（有効にするとファイルがバージョン管理され、ファイルを削除した場合に復元できたりします）
　タグ : `タグの追加`をクリックして、キー:`Name`と値:`board-dev-contents-XXXXXXXXXXXX`を入力
　サーバー側の暗号化 : `無効にする`

`バケットを作成`をクリックするとバケットが作成されますので、作成できたかを確認してください

* 試しに、`アップロード`→`ファイルを追加`からなんでもいいのでファイルをアップロードしてみてください
* アップロードしたファイルは、あとでEC2からS3に接続したときの確認に使います


##4-2.VPCエンドポイントを作成

* EC2からS3にアクセスするために、VPCに通信の出入口(エンドポイント)を作ってあげます
* 以下のエンドポイントの作成で出てくるポリシーとは、AWSリソース(S3など)にアクセスするための権限設定のことで、誰が何に対してどういう操作を許可・拒否するかという内容になっています
* S3についてのアクセス制御については次を参考にしてください　→　[S3のアクセスコントロールまとめ](https://qiita.com/ryo0301/items/791c0a666feeea0a704c)


AWSマネジメントコンソール→VPC→エンドポイント→`エンドポイントの作成`

　サービスカテゴリ : `AWSサービスを選択`にチェック
　サービス名 : `com.amazonaws.ap-northeast-1.s3（タイプはGateway)`を選択
　　※　S3でキーワード検索するとすぐ見つかります
　VPC : `board-dev-vpc(1-1で作成したVPC）`
　ルートテーブルの設定 : `パブリックサブネット（board-dev-public-subnet01）に関連づけられているルートテーブル`にチェック
　ポリシー : `カスタム`にチェックを入れて、`ポリシー作成ツール`をクリックしてその先で作成したポリシーを貼り付けます（以下ポリシーの作成方法を参照）
　タグ : Name : `board-dev-vpc-endpoint`

`エンドポイントの作成`をクリックするとエンドポイントが作成され、指定したルートテーブルにゲートウェイへのルーティングが追加されます

**ポリシーの作成方法**
**Step1**
Select Type of Policy : `VPC Endpoint Policy`
**Step2**
Effect : `Allow`
Principal : `*`
AWS Service : `Amazon S3`
Actions : 右の`All Actions`にチェック
Amazon Resource Name (ARN) : `arn:aws:s3:::board-dev-contents-XXXXXXXXXXXX,arn:aws:s3:::board-dev-contents-XXXXXXXXXXXX/*` (XXXXXXXXXXXXは、4-1でS3のバケットを作成したときのAWSのアカウント番号に置き換えてください）

最後に`Add Statement`を押して、下に表示された Step3の`Generate Policy`を押して表示されたポリシーを表示→コピーして元の画面のポリシーの部分に貼り付けしてください


##4-3.S3アクセス用のIAMユーザーを作成

* IAMとは、Identity and Access Managementの略で、直訳すればIDとアクセス管理、要するに認証機能のことです
* S3にアクセスできる権限だけをもったユーザーを作成して、その権限を使ってS3にアクセスします(セキュリティを高めるため)

AWSマネジメントコンソール→IAM→左のメニューのユーザー→`ユーザーを追加`

　ユーザー名 : `s3-access`
　AWS 認証情報タイプの選択 : `アクセスキー - プログラムによるアクセス`だけにチェックを入れる
　`次のステップ:アクセス制限`をクリック

　アクセス許可の設定 : `既存のポリシーを直接アタッチ`を選択
　ポリシーのフィルタでs3を検索し、ポリシー名 : `AmazonS3FullAccess` にチェックを入れる
　`次のステップ:タグ`をクリック

　タグの追加 (オプション)はスキップしてください
　`次のステップ:確認`をクリック

作成内容を確認したら、`ユーザーの作成`をクリックしてユーザーを作成後、`アクセスキーID`と`シークレットアクセスキー`が表示されますので、それを控えておくか、`.csvのダウンロード`をクリックしてCSVファイルでダウンロードしておいてください


##4-4.EC2でAWS CLIを使うための設定

* CLIとは、Command Line Interfaceの略で、コマンドを使用してAWSサービスとやり取りするためのツールです
* EC2からS3にアクセスするためにAWSというコマンドを使うのですが、そのコマンドを使えるようにします
* EC2には最初からAWS CLIがインストールされていますので、以下のアクセス設定をするだけでCLIが使えるようになります
* 4-3.S3アクセス用のIAMユーザーを作成で作成したIAMユーザの、アクセキーIDとシークレットアクセスキーを使用します
* 参考　→　[AWS CLI 設定の基本](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-quickstart.html)

```bash
$ aws configure
AWS Access Key ID [None]: 4-3の最後で保存したアクセスキーID
AWS Secret Access Key [None]: 4-3の最後で保存したシークレットアクセスキー
Default region name [None]: ap-northeast-1
Default output format [None]: json

~/.aws/config　（設定ファイル）が作成されますので、以下のコマンドで内容を確認してください
$ cat ~/.aws/config
[default]
output = json
region = ap-northeast-1
```

##4-5.EC2からS3へアクセスする

* S3のバケットの画面から、4-1.S3のバケットを作成でアップロードしたファイルを確認してみます
* S3のバケットの中身を確認（以下XXXXXXXXXXXXの部分は、4-1でS3のバケットを作成したときのAWSのアカウント番号に置き換えてください）

```bash
$ aws s3 ls s3://board-dev-contents-XXXXXXXXXXXX/
2021-10-31 22:57:28       3278 test.jpg
このように、アップロードとしたファイルが見えていればS3に接続できています
```

##4-6.EC2にComposerをインストール

* PHPのアプリから、S3のファイルを参照したり、S3にファイルをアップロードしたりするために、AWS SDK for PHPというものが必要になります
* SDKとは、Software Development Kitの略で、ソフトウェアの開発キットです
* AWS SDK for PHPをEC2にインストールするために、まずComposerが必要になるのでそれをインストールします
* Composerとは、PHPのライブラリやパッケージを管理するツールです
* 次のサイトを参考に以下手順を作成しました　→　[Download Composer](https://getcomposer.org/download/)

```bash
$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ php -r "if (hash_file('sha384', 'composer-setup.php') === '906a84df04cea2aa72f40b5f787e49f22d4c2f19492ac310e8cba5b96ac8b64115ac402c8cd292b8a03482574915d1a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
$ php composer-setup.php
$ php -r "unlink('composer-setup.php');"

composer.pharを移動
$ sudo mv composer.phar /usr/local/bin/composer

composerの実行ファイルを実行
$ php /usr/local/bin/composer
```

##4-7.EC2にAWS SDK for PHPをインストール

* 続いて、Composerを使ってAWS SDK for PHPをインストールします

```bash
例として、/var/www/html/boardにインストールするとします
$ cd /var/www/html/board
$ composer require aws/aws-sdk-php
composer.jsonとcomposer.lockと/vendorが作成されます

gitを使っている場合は/vendorをgit管理から外しておきます
$ echo "vendor" >> .gitignore
```

##4-8.EC2にphpdotenvをインストール

* 最後に、Comoserを使ってphpdotenvをインストールします
* phpdotenvとは、PHPの環境変数設定ライブラリです
* 名前のとおり環境設定ファイルとして.envというファイルを作って、そこからS3へのアクセス情報を読み込むことにします（ソースにアクセスキーをベタ書きするのはよろしくないため）

```bash
例として、/var/www/html/boardにインストールするとします
$ cd /var/www/html/board
$ composer require vlucas/phpdotenv

.env(環境設定ファイル)を作っておきます
$ touch .env

gitを使っている場合は.envをgit管理から外しておきます
$ echo .env >> .gitignore
```

##4-9.環境設定ファイルの作成

* .envファイルの中身に以下を記載してください（アクセスキーIDとシークレットアクセスキーは、4-3.S3アクセス用のIAMユーザー作成の最後に控えたものです）
* BUCKET_NAMEのXXXXXXXXXXXXの部分は、4-1でS3のバケットを作成したときのAWSのアカウント番号に置き換えてください

```php
AWS_ACCESS_KEY_ID=IAMユーザーのアクセスキーID
AWS_SECRET_ACCESS_KEY=IAMユーザーのシークレットアクセスキー
S3_BUCKET_NAME=board-dev-contents-XXXXXXXXXXXX
```

##4-10.PHPアプリからS3を操作

* 最後に、PHPのソースを書き換えて、アプリからS3へ対しての操作ができるか動作確認してみましょう
* 構築に問題がなければ、アプリからアップロードした画像がS3に保存され、保存した画像がS3から読み込まれて画面に表示できるはずです
* SDKを使ってアップロード・削除・参照するサンプルコードは以下です

###共通設定

```php
// SDKの読込
require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;

// .envを使用
Dotenv\Dotenv::createImmutable(__DIR__)->load();
$access_key = $_ENV['AWS_ACCESS_KEY_ID'];
$secret_key = $_ENV['AWS_SECRET_ACCESS_KEY'];
$bucket = $_ENV['S3_BUCKET_NAME'];

// S3クライアントを作成
$s3_client = new S3Client([
        'version' => 'latest',
        'credentials' => [
                'key' => $access_key,
                'secret' => $secret_key
                ],
        'region' => 'ap-northeast-1'
        ]);
```

###S3に画像ファイルをアップロード

```php
// ファイルアップロード
$res = $s3_client->putObject([
        'Bucket' => $bucket,
        'Key' => 'アップロードファイル名（拡張子付き）',
        'SourceFile' => 'ファイルデータ',
        // ACL(アクセスコントロールリスト)はパブリックアクセスさせずに署名付きURLで参照するためにコメントアウト
        //'ACL' => 'public-read',
        'mime_content_type' => 'ファイルのMIMEタイプ'
        ]);
```

###S3の画像ファイルを削除

```php
// ファイル削除
$res = $s3_client->deleteObject([
        'Bucket' => $bucket,
        'Key' => 'S3でのファイル名'
]);
```

###S3の画像ファイルを表示

* 画像の表示には、署名付きURLというものを使用します
* そもそもパブリックアクセスをブロックしているので、画像のURLを知っていたとしてブラウザで直にアクセスしたとしても、画像は表示できないようになっています
* 署名付きURLについての参考　→　[【AWS S3】S3 Presigned URLの仕組みを調べてみた](https://qiita.com/tmiki/items/87697d3d3d5330c6fc08)

```php
// 署名付きURL用のコマンド生成
$cmd = $s3_client->getCommand('GetObject', [
    'Bucket' => $bucket,
    'Key' => 'S3でのファイル名'
]);

// 署名付きURLの作成（1分間だけ有効なURLを作成する場合）
$request = $s3_client->createPresignedRequest($cmd, '+1 minutes');

// 署名付きURLの取得
$presigned_url = (string)$request->getUri();

$presigned_url を imgタグのsrcに指定すればアップロードした画像の表示ができます
```

##4-11.S3のまとめ

* S3はファイルストレージ
* EC2からS3へのアクセスはVPCエンドポイントを使って行い、パブリックアクセスはさせない
* 画像の参照には、署名付きURLを使う
* バケットを削除するときは、バケットを空にしないと削除できないので注意してください


#5. おわりに

チュートリアルお疲れさまでした。すべて終わってから最初のネットワーク構成図を眺めてみると、各AWSリソースのつながりがよく分かるかなと思います。

AWSをほぼ触ったことない状態からチュートリアル作成のために何度も環境を作ったり壊したりするうちに、自然とAWSの理解が深まった気がします。みなさんにとっても、今回のチュートリアルで少しでもAWSについての理解が進みましたらうれしく思います。

今後は、上記のネットワーク構成をコード化して環境を構築するCloudFormatinというサービスを使ってみたり、WEBサービスそのものをLambdaなどを使ったサーバレスの構成で作ってみたりすることをやってみたいと思っています。

ありがとうございました。