AWS サービスを用いて Web アプリケーションを作成する

# はじめに
### 概要
本記事では、 AWS コンポーネント・アーキテクチャを用いて以下の構成で Web アプリケーションを構築する手順を記載しています。
![aws.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/052e6708-f809-18d5-c8c0-c97a676cba42.png)
基本的な AWS サービス
- CloudFront
  - ユーザーへの静的および動的なウェブコンテンツ (.html、.css、.js、イメージファイルなど) の配信を高速化するサービス。フロントエンドに使用。
- S3
  - オブジェクトストレージサービス
- ALB
  - Web サービスにおける負荷を分散させるロードバランシングサービス。バックエンドに使用。
- ECS ( Fargate )
  - フルマネージドコンテナオーケストレーションサービス。コンテナ化されたアプリケーションを簡単にデプロイ、管理、およびスケーリングできる。
- RDS
  - クラウド内でリレーショナルデータベースのセットアップ、運用、およびスケーリングを簡単に行うことのできるマネージド型サービス

補足的なサービス
- AWS WAF
  - Amazon CloudFront、Application Load Balancer (ALB) 上で動作する AWS の提供するクラウド型 WAF のサービス。アクセス制限をかけることができる。
- Route53
  - 可用性が高くスケーラブルなドメインネームシステム (DNS) ウェブサービス。ドメイン名を独自のものにする ( HTTPS 通信を可能にする ) 際に使用。
- ACM
  - ウェブサイトやアプリケーションを保護するパブリックおよびプライベート SSL/TLS X. 509 証明書およびキーの作成、保存を行うことができる。 Web サイトを独自ドメインにする際の証明書の発行に使用。
### 目的
#### 対象者

- AWS をこれから触り始めようとする方
- AWS を触り始めてサービス単体は理解しつつあるが、Web システム開発する際、どういう構成がいいか・どう構築していけばいいか分からない方

以上の対象者が、AWS サービスを用いて Web システムを実際に構築できるようになることを目的としています。

# S3 と CloudFront
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/8a4ebb97-15ca-86ea-77e0-c39dcd71276e.png)

まず初めに、ユーザーが CloudFront を介して S3 内の情報をアクセスできるようにします。

## S3 にバケットを作成

Amazon S3 からバケット、「バケットを作成」を選んで任意のバケット名と AWS リージョンを選択します。今回の構成ではリージョンを「アジアパシフィック(東京) ap-northeast-1 」、その他の設定はデフォルトで作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/e1b5320d-057d-e1f7-e310-9c9d29b77bc3.png)

作成したバケットを選択し、プロパティタブから静的ウェブサイトホスティングを編集し、以下の画像のように設定して保存します。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/2a7272bc-7ffb-49df-ee18-e419e13f56f0.png)

また、アクセス許可タブからパブリックアクセスのブロック(バケット設定)を編集し、すべてチェックが外れた状態に設定して保存します。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/ed73de2b-51aa-093a-1c7f-e4208b092278.png)

同じように、アクセス許可タブからバケットポリシーを編集し、ポリシーに以下のコードを設定して保存します。

```
{​​​​​​​
    "Version": "2012-10-17",
    "Statement": [
        {​​​​​​​
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": ["s3:GetObject"],
            "Resource": ["arn:aws:s3:::Bucket-Name/*"]
        }​​​​​​​​​​​​​​​​​​​​​
    ]
}​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
```
## 作成したバケットにフロントエンドをアップロード

バケットのオブジェクトタブからアップロードを選択し、ビルドして作成されたフロントエンドの実行ファイルをアップロードします。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/63dd5cbf-c6a4-085c-b626-87e7168e9500.png)

## S3 から Web サイトを確認
バケットのプロパティタブにある静的ウェブサイトホスティング内の、バケットウェブサイトエンドポイントの URL から S3 にアップロードしたフロントエンドコードが確認できます。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/5e7b56c3-b675-39ae-7c7e-8e1aaa87236c.png)

## CloudFront にディストリビューションを作成
AWS CloudFront からディストリビューションの作成を選択します。オリジンドメインには、作成した S3 のバケットウェブサイトエンドポイントの URL を指定し、その他の設定はデフォルトで作成します。 CloudFront からは、一般タブのディストリビューションドメイン名から S3 内のフロントエンドコードが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/99a88a11-adb9-dffa-f085-d3509b71a5c0.png)

## 補足 : アクセス制限をかける
### S3 を CloudFront からのみアクセスできるようにする
作成したオリジンを編集します。カスタムヘッダーの追加を選択し、ヘッダー名は Referer 、値には任意の文字列を指定して変更を保存します。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/beecf906-3a35-ecfe-a96d-1184f7bc2621.png)

S3 のバケットポリシーを以下のように変更して保存します。
```
{​​​​​​
    "Version": "2012-10-17",
    "Statement": [
        {​​​​​​
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": ["arn:aws:s3:::Bucket-Name/*"]
            "Condition": {​​​​​​
                "StringLike": {​​​​​​
                    "aws:Referer": "任意の値"
                }​​​​​​
            }​​​​​​
        }​​​​​​
    ]
}​​​​​​
```

### CloudFront を任意の IP アドレスからのみアクセスできるようにする
#### AWS WAF を作成する
- AWS マネジメントコンソールから WAF & Shield を選択し、「 Create web ACL 」を選択します。
- Web ACL detailsの設定を行います。
  - Resource type に「 CloudFront distributions 」を指定
  - 任意の Name を指定
  - Description を指定 ( ex. for CloudFront IP Filter )
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/669e1b16-798a-5cb6-b4bb-5679486c85ce.png)

- Associated AWS resources の設定を行います。
  - 「Add AWS resources」を選択
  - Name にした CloudFront のディストリビューション名を選択
  
- Add rules and rule groups の設定を行います。
  - Rules の指定なし
  - Default action は「 Block 」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/e35a160f-286a-508d-af90-b941872ba55f.png)

その他の設定はデフォルトで作成します。
#### IP Set を作成する
- 左メニューのIP setsを選択します。
- リージョンに「 Global (CloudFront) 」を選択、「 Create IP set 」を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/cdcbff94-5b6a-0513-0549-326336509138.png)

- IP set details の設定を行います。
  - 任意の IP set name を指定
  - Description を指定
  - Region に「 Global (CloudFront) 」を選択
  - IP version に「 IPv4 」を選択
  - IP addresses に許可する IP アドレスを指定 ( 例 : 10.0.0.0/32 , 社用 VPM IP アドレス )
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/302a7552-9792-6634-255a-95f03663762f.png)

#### ACL にルールを作成

- WebACLs を選択、 Rules タブを選択します。
- 「 Add rules 」の「 Add my own rules and rule groups 」を選択します。
- Rule の設定を行います。
  - Rule type に「 Rule builder 」を選択
  - Rule Name に Rule 名を指定
  - Type に「 Regular rule 」を選択
  - If a request に「 matches the statement 」を選択
  - Statement を設定する。
    - Inspect に「 Original from an IP address in 」、 IP set に先ほど作成した IP set を選択
  - IP address to use as the originating address に「 Source IP address 」を選択

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/43b19d32-b59b-d0cd-8452-6e38a2d432e7.png)

# VPC と ALB 、 Fargate
![aws.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/0e6b53ca-2c10-855a-2174-f0a2c70b6ebc.png)

## Amazon ECR にプライベートリポジトリを作成
- Amazon ECR でリポジトリの作成を選択します。
  - 可視性設定はプライベートを選択
  - リポジトリ名に任意の名前を入力
![23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/da707122-6f99-c94e-4820-d4ef78dc37ba.png)


## Docker イメージを ECR にアップロード
※DockerイメージはWindows上で作成ツールを使用すると料金がかかるため、 WSL ( Ubuntu ) 上で作成
- Dockerイメージを作成したいファイルの直下にDockerfileを作成します。( 以下サンプル )
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/ce07652b-dbd2-f5bb-2ac8-5a1e21eef36a.png)
- 作成したリポジトリから、プッシュコマンドを表示を選択します。
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/e792dcbb-5ba1-cbb8-5bc3-a6cebf1d9657.png)
- プッシュコマンドを順番に実行します。
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/3a16e7ba-3489-1d61-098e-1e70e2cb9add.png)
※ AWS cli を最新にする必要があります。( 公式ドキュメント : https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html )
※ aws configureの情報がないとエラーがでるので、アクセスキーとシークレットアクセスキーを取得する必要があります。
  - 公式ドキュメント( https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-quickstart.html ) を参考に、 Access key ID とSecret access key の書かれている csv ファイルをダウンロード
  - AWS Management Console にサインインして、IAM コンソール (https://console.aws.amazon.com/iam/) を開く
  - ナビゲーションペインで 「 Users 」 (ユーザー) を選択
  - アクセスキーを作成するユーザー名を選択し、「 Security credentials (セキュリティ認証情報) 」 タブを選択
  - 「 Access keys (アクセスキー) 」 セクションで、「 Create access key (アクセスキーを作成) 」 を選択
  - 「 Download .csv file.csv 」 (キーファイルのダウンロード) を選択してキーペアをダウンロード
※このダイアログボックスを閉じた後で、シークレットアクセスキーに再度アクセスすることはできません。

## VPC を作成
- VPC を作成を選択します。設定はデフォルトで作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/4316be72-b060-0e13-efc4-ffd347d36dd8.png)

### パブリックサブネットを作成
- VPC からサブネットを選択し、「サブネットを作成」を選択します。
  - 作成した VPC を選択
  - 任意のサブネット名を入力
  - 任意のアベイラビリティゾーンを選択
※異なるアベイラビリティゾーンで、2つのパブリックサブネットを作成してください。
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/0e13843a-c431-a71a-5401-073df25edee5.png)

### インターネットゲートウェイを作成
- VPCからインターネットゲートウェイを選択し、「インターネットゲートウェイを作成」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/56091081-0242-d5e9-8be1-195a3ed8a7c3.png)

## ALB を作成
### セキュリティグループを作成
- EC2 からセキュリティグループを選択し、「セキュリティグループを作成」を選択します。
  - 作成した VPC を選択
  - インバウンドルールに HTTP を追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/a560524e-4f1f-949c-19d8-5de8f3f04b6b.png)

### ALB を作成
- EC2 からロードバランサーを選択し、「 Create load balancer 」を選択します。
  - Load balancer types に Application load Balancer を選択して作成
  - VPC は作成したものを選択
  - セキュリティグループは作成したものを選択
サブネットも作成したものを使用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/a5c63a68-939e-97fa-6b2c-05cd3a602af8.png)

## ECS ( Fargate ) を作成
### タスク定義を作成
- ECS からタスク定義を選択し、「新しいタスク定義の作成」を選択します。
  - コンテナのイメージURIには作成した ECR リポジトリにアップロードしたイメージ URI を使用
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/855db48b-5142-d046-85d9-0f7d5e2bdb2b.png)

  - タスクロールはなし、タスク実行ロールはデフォルト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/1d715458-9cdf-ee81-b08d-9415d2207ec2.png)

### クラスターを作成
- ECS からクラスターを選択し、「クラスターの作成」を選択します。
  - VPC は作成したものを選択
  - サブネットは作成したパブリックサブネット2つを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/44aab83a-d0e7-4511-a047-91b946815443.png)

### ターゲットグループを作成
- EC2 からターゲットグループを選択し、「 Create Target Group 」を選択します。
  - ターゲットタイプに IP addresses を選択
  - その他は変更せず作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/55523d47-fdeb-5b3f-2918-145fad4b64ca.png)

### サービスを作成
- ECS からクラスター、作成したクラスターを選択し、サービスタブで「作成」を選択します。
  - タスクの数は2に設定
  - タスク定義は作成したものを選択
  - VPC は作成したものを選択
  - サブネットは作成したパブリックサブネット2つを選択
  - セキュリティグループはイメージのポート番号を通すものを作成・選択 ( 例 : プロトコルTCP ポート番号3000 )
  - ターゲットグループは作成したものを選択
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/726b95d6-45c9-1ae8-a014-52dcc9febfe6.png)

### ALB から接続確認
EC2 からロードバランサーを選択し、作成したロードバランサーの DNS 名でコンテナに接続できます。
![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/123732f4-d0a4-2a96-457d-16428d87f712.png)

## 補足 : HTTPS 通信ができるようにする
- AWS ACM で証明書を発行します。
※無料のパブリック証明書をリクエストし、完全修飾ドメイン名は AWS Route53 で後につくるレコード名と一致させる必要があります。各 AWS サービスごとに1つ作成してください。また、 CloudFront に証明書を紐づける際はリージョンを「バージニア北部」にする必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/2db6e9e4-6116-2115-5ba5-21a7cb2743be.png)

### CloudFront の場合
- 作成したディストリビューションから、設定を編集します。
  - 代替ドメイン名に完全修飾ドメイン名を追加
  - カスタム SSL 証明書に、先ほど作成した証明書を登録
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/78fca6bd-b2d5-4670-0f14-3aa87b8aef2a.png)

- AWS Route53 で先ほど作成されたレコードを選択して編集します。
  - レコード名を完全修飾ドメイン名と合わせる
  - レコードタイプを A-IPv4 に変更
  - エイリアスにチェックを入れて、トラフィックのルーティング先に「 Cloudfront ディストリビューションのエイリアス」を選択
  - ディストリビューションに自分たちが作成した CloudFront のディストリビューション名を選択

### ALB の場合
- HTTPS をインバウンドルールに入れたセキュリティグループを作成します。
- 作成したセキュリティグループを ALB に紐づけます。
![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/f07575c6-54b8-5ce7-ae62-e2bf2f2935d0.png)
- 作成した ALB を選択し、Listener タブから Add Listener を選択します。
- Protocol:Port に HTTPS:443 を選択したリスナーを追加します。
![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/eadda396-1b02-2975-9648-9d752619fcdb.png)
- AWS Route53 にレコードを作成します。
  - トラフィックのルーティング先には、 ALB と CLB へのエイリアスを選択し、作成した ALB のドメイン名を選択します。
![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/f7669594-c86c-431e-296e-bf0338f00711.png)

## 補足 : ALB と Fargate へのアクセス制限
### ALB にIPアドレス制限をかける
- ALB　で作成したリスナーを選択し、 Rules タブから Manage rules を選択して追加します。
  - IF に IP アドレスを追加、 THEN にターゲットグループを設定
  - デフォルトアクションには、 THEN で固定レスポンスを返すように設定
![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/d48edae7-1300-130e-de4e-0f598518fa6e.png)

### Fargate を ALB からしかアクセスできないようにする
- 作成したサービスにすでに設定しているセキュリティグループのインバウンドルールを編集します。
  - ソースに、 ALB で用いているセキュリティグループを選択して変更
![19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/eab15379-a9a0-a0c6-244d-5f3afbdb927c.png)

# RDS を作成
![20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/ae8c5e59-abd3-4cd9-27bb-805a8c419c30.png)

## プライベートサブネット作成
### ルートテーブルを作成
- VPC は作成したものを使用します。
※作成したインターネットゲートウェイがルートに設定されていないものを用意します。
![21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/b797bce2-ebc8-8476-c450-a1e42cc3b15e.png)

### プライベートサブネットを作成
- パブリックサブネットと同じ数作成します。 ( 今回は2つ )
- 作成したルートテーブルを紐づける

## セキュリティグループを作成
### EC2 のセキュリティグループを作成
- VPC は作成したものを選択します。
‐ インバウンドルールは SSH とすべての ICMP IPv4 を選択します。
### RDS のセキュリティグループを作成
- VPC は作成したものを選択します。
- インバウンドルールは MySQL TCP/3306 を選択します。

## DB サブネットグループの作成
- Amazon RDS のサブネットグループを作成します。( DB サブネットグループ)
  - アベイラビリティゾーンはプライベートサブネットを作成したアベイラビリティゾーンを選択
　- サブネットの選択では作成したプライベートサブネットを選択
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/9520bde4-7d26-6cee-c040-cbc60f5e1d19.png)

## EC2 ( RDS にアクセスするための踏み台)を作成
- インスタンスを起動します。
- OS イメージは AmazonLinax2 を選択します。
- キーペアを作成します。
- サブネットはパブリックサブネットを指定します。
- VPC とセキュリティグループは作成したものを使用します。
- パブリック IP の自動割り当ては有効化します。

## RDS を作成
- MySQL を選択します。
- 可用性と耐久性は単一の DB インスタンスを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/d5b064c0-a1e6-57c8-1e2a-5f535f2d0ed5.png)
- パスワードは任意のものを入力します。
- インスタンスの設定では、任意の大きさを選択します。( DB 容量によってかかる料金が変わります。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/fa36b934-4d1b-318a-8c40-a725144d0a99.png)
- VPC とサブネットグループは作成したものを選択します。
- パブリックアクセスはなしを選択します。
- 追加設定を開き、データベース名を入力しておきます。

## EC2 から RDS への接続確認
- 作成した EC2 を起動し、接続します。
- SSH クライアントを選択し、一番下のコマンドをコピーしてコマンドプロンプトで実行します。( yes/no はすべて yes を入力)
![22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1781492/2862cf5f-1f75-bdce-ff91-f1655b0b5018.png)
- 以下のコマンドを実行します。
`$ sudo yum update`
`$ sudo yum install mysql`
- MySql に接続します。
`$ mysql -u (RDSで設定したユーザー名) -p -h (RDSのエンドポイント)`
  - RDSで設定したパスワードを入力