ECS・RDSを使って初めてのAWS環境構築をしてみた

# はじめに
2020の11月に開催された[JPHACKS2020](https://jphacks.com/)に参加し、本戦に進むことができました！
その際、以前から興味があった**AWS** (**Amazon Web Service**)を初めて使ってインフラ環境の構築をしたので、その設計についての記事を書こうと思います。

# 開発したサービスについて
開発したサービスは「**Effective Work**」という名前です。
（サービスの紹介動画は[こちら](https://www.youtube.com/watch?v=IdvRumHTEvc&feature=youtu.be)）

ハッカソンのテーマが「**〇〇 × Tech**」だったので、僕たちは「**Tele × Tech**」というテーマを軸にサービスを考えました。
サービスの内容を簡単に説明すると、ユーザーが座っている椅子につけられたセンサーのデータを元にリモートワーク中の**集中力を測定**し、集中力のレコードをブラウザ上で確認できたり、集中力が下がった・下がりそうなユーザーにSlackで通知をして休憩を促す、といったものです。それにより、**集中力が下がる前に**適切な休憩取り、仕事時間全体として**高い生産性**を保ってもらうことを目的としています。

# 前提条件
 - aws cliのインストール済
 - dockerのインストール済
 - AWSについての基本的な知識
 - ネットワークについての基本的な知識

# サービスの全体構造
先頭で書いたとおり、今回はAWSの各種サービスを使ってインフラ環境を構築しました。全体的な構成は以下のようになっています。
![effective_work_architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/cb69e78a-b1ee-92ab-5f26-aad3d8f86e66.png)
バックエンドのAPIサーバーには**ECS** (**Elastic Container Service**)を使い、データベースとして**RDS** (**Relational Database Service**)でPostgreSQLを使用しました。
フロントエンドはReactで開発したソースコードをbuildして静的ファイルを生成し、それを**S3** (**Simple Storage Service**)に置いて配信しています。

この記事では、バックエンド部分の**ECS**と**RDS**についての設計について説明します。（その他のサービスについては別の記事で書く予定です。）

# VPC
## VPCの作成
まずは**VPC** (**Virtual Private Cloud**)の作成をします。
VPCはAWSの一番基本となるサービスで、ユーザー専用のネットワーク環境を構築することができます。
今回はCIDRを "10.0.0.0/16" にして "effective-work-vpc" という名前で作りました。
![スクリーンショット 2020-12-12 16.36.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/e445e6bb-71d9-097d-9957-ebb776523272.png)

## サブネットの作成
続いてサブネットの作成です。サブネットは先程作成したVPCのネットワークをさらに細かく分ける機能で、今回はインターネットに接続する**パブリックサブネット**とインターネットに接続しない**プライベートサブネット**を、2つのAZ (アベイラビリティーゾーン)にそれぞれ1つずつ作成しました。

- effective-work-subnet-public-a(10.0.1.0/24)
- effective-work-subnet-public-c(10.0.2.0/24)
- effective-work-subnet-private-a(10.0.10.0/24)
- effective-work-subnet-private-c(10.0.20.0/24)

![スクリーンショット 2020-12-12 16.41.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/6135db58-4c07-cce4-a9fa-25cbd58efb52.png)

## ルートテーブルの関連付け
ここで、作成したパブリックサブネットがインターネットに接続できるように、**インターネットゲートウェイ**をデフォルトゲートウェイに登録した**ルートテーブル**をサブネットに関連付ける必要があります。

まず、新たにインターネットゲートウェイ "effective-work-internet-gateway" を作成し、先ほど作成したVPCにアタッチします。
![スクリーンショット 2020-12-12 16.56.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/7b605f68-ab0e-a0b0-2d5c-c5e9e98ea2bd.png)
![スクリーンショット 2020-12-12 16.56.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/745076f7-8359-5c1b-fcb6-07f3bb92d2fe.png)

次に、新たにルートテーブル "effective-work-route-table-public" を作成し先程のインターネットゲートウェイをデフォルトゲートウェイとして登録しておきます。
![スクリーンショット 2020-12-12 16.58.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/f1dfa200-ed09-f177-e4ee-5ec37a630288.png)
![スクリーンショット 2020-12-12 16.59.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/2c765686-289a-7aad-4586-d97fd3883634.png)

そして、作成したルートテーブルを先ほど作成した2つのパブリックサブネットに関連付けます。
![スクリーンショット 2020-12-12 17.24.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/6d01ae2a-1874-eee1-8f48-f00e4724cde0.png)
![スクリーンショット 2020-12-12 17.24.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/63be6e17-1ddb-d4e8-8002-962aed8f09d9.png)

これで、VPCの設定はとりあえず終了です。続いてRDSの設定に移りましょう。

# RDS
参考：[Dockerコンテナで作ったアプリをECS+RDSでデプロイする](https://qiita.com/saki-engineering/items/8e1c4e8ecbe3f3492b40#3-rds%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E4%BD%9C%E6%88%90)

上記の記事を参考にしてRDSのインスタンスを作成しました。

## DBサブネットグループの作成
まずはRDSのマネジメントコンソールを開き、サブネットグループのページを開きます。そして、新たに"effective-work-subnet-group"という名前のサブネットグループを作成します。
※ **VPCのコンソール画面でなく、RDSのコンソール画面のサブネットグループなので注意！**
![スクリーンショット 2020-12-12 17.33.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/5a9f39af-c7f0-8b01-8009-78c54964f4e5.png)

ここで、AZは先ほど作成したVPCのサブネットを配置した "ap-northeast-1a" と "ap-northeast-1c" を選び、VPCのサブネットは先ほど作成した2つのプライベートサブネットを指定します。
![スクリーンショット 2020-12-12 17.29.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/09c6714f-180f-fddc-609b-3b50b1667c9d.png)

## RDSインスタンスの作成
続いて、RDSインスタンスを作成していきます。今回はにPostgreSQLを選択しました。
![スクリーンショット 2020-12-12 17.42.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/ef7b24f6-9c4d-5a18-a4d6-30f6e6594c97.png)
![スクリーンショット 2020-12-12 17.42.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/4ae8ccf5-9da3-c168-65bb-b6c3cc56e9b8.png)
![スクリーンショット 2020-12-12 17.43.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/323e0a24-0744-5e9b-7f90-f216b552f6b3.png)
![スクリーンショット 2020-12-12 17.44.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/9b8d1274-b23a-534b-a780-e2c90541e0a5.png)


VPCは先ほど作成したものを選択します。サブネットグループも同様です。また、セキュリティグループは新たに "effective-work-security-group" という名前のものを作成しました。
![スクリーンショット 2020-12-12 17.46.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/7328dff9-90bf-0734-b155-70959e234bc8.png)

また、Additional configurationの欄を開いて任意の初期データベース名を設定しましょう。
![スクリーンショット 2020-12-12 20.38.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/f2ea78be-84cb-5563-9713-5b90039e4e59.png)

DBインスタンスを作成するとこのような表示が画面上部に出てくるので、 "View credential details" を押してパスワードを忘れずに記録しておきましょう。（自分で決めたパスワードを設定した場合はそれを覚えておけば大丈夫です。）
![スクリーンショット 2020-12-12 17.50.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/ba691ffd-02ab-0562-9cd2-0e6e77d497ea.png)

最後に、作成したDBインスタンスのエンドポイントをメモしておきます。インスタンス詳細画面の "Connectivity & security" 欄に記載してあるので、先ほど設定した「管理者ユーザー名」「管理者ユーザーパスワード」「初期データベース名」と合わせて保管しておきましょう。これらの情報は他人には絶対に知られないように大切に保管してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/64be9ab6-641a-5a65-5423-0b871a867a6e.png)

# ECS
## IAMユーザーの作成
最後に、ECSの設定をします。
まず初めに、コマンドラインからECRにアクセスできるように、ECRにアクセスする権限を持つ**IAM**(**Identitity and Access Management**)ユーザーを作成します。

1. IAMのコンソール画面から「ユーザー」欄を開き、「ユーザーの追加」をクリックする。
2. 任意のユーザー名を入力し、「プログラムによるアクセス」にだけチェックを付けて次へ進む。
3. 「既存のポリシーを直接アタッチ」を選択し、「AmazonEC2ContainerRegistryFullAccess」にチェックを入れて次に進む。
4. タグを追加したければ追加し、最後に確認へ進み、「ユーザーの作成」をクリックする。
5. 表示される認証情報「**アクセスキーID**」と「**シークレットアクセスキー**」をメモしておく。

IAMユーザーの作成が終わったら、ローカル環境にあるPCのコマンドラインで`aws configure`を実行し、アクセスキーやシークレットアクセスキーの入力を求められるので先ほどメモしたものを入力します。

## クラスターの作成
ECSのコンソール画面から「**クラスター**」を選択し、クラスターの作成をクリックします。
クラスターの主要項目の設定例を下記に示しておきます。

【クラスターテンプレート】　EC2 Linux + ネットワーキング
【クラスター名】　任意（今回は "effective-work-cluster" に設定）
【EC2 インスタンスタイプ】　tc.micro
【インスタンス数】　1
【キーペア】　あらかじめ作成しておいたものを選択
【VPC】　先ほど作成した "effective-work-vpc"
【サブネット】　先ほど作成した2つのパブリックサブネット
【Auto assign public IP】　SSH接続をしてインスタンスの状態を確認したいためEnable(有効）にする
【セキュリティグループ】　新しいセキュリティグループを作成
【セキュリティグループのインバウンドルール】　ローカルのPCからSSH接続をしたいためCIDRブロックを0.0.0.0/0にし、ポート22を指定。（HTTPのインバウンドルールは後ほど設定する。）
【コンテナインスタンスのIAMロール】　ecsInstanceRole

これでクラスターの作成は完了です。

## ECRの作成 ＆ イメージのプッシュ
続いてAWS上のコンテナイメージ置き場である**ECR** (**Elastic Container Repository**)の設定をします。ECSのコンソール画面からECRの欄を開き、新規リポジトリを作成します。
作成すると下記のようなポップアップが出てくるので、「プッシュコマンドの表示」をクリックして書いてある通りに操作を行い、リポジトリにdockerイメージをプッシュします。
![スクリーンショット 2020-12-12 21.42.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/fda92015-0e53-d147-afe5-c7a2df3d4653.png)
![スクリーンショット 2020-12-13 13.46.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/c0cfa111-4486-9ffa-fefb-c34def6bf967.png)

## タスク定義の作成
続いてタスク定義を行います。
ECSのコンソール画面からタスク定義を選択し、「新しいタスク定義の作成」をクリックします。
タスク定義の主要項目の設定例を下記に示しておきます。
【起動タイプの互換性】　EC2
【タスク定義名】　任意（今回は "effective-work-task" ）
【タスクロール】　なし
【ネットワークモード】　awsvpc
【タスクの実行ロール】　ecsTaskExecutionRole
【コンテナの定義】
　【コンテナ名】　任意（今回は "effective-work-container" ）
　【イメージ】　先ほどアップロードしたイメージのURIを記入する。
　【ハード制限】　128
　【ポートマッピング】　80, tcp
　【環境変数】　Flaskでデータベースに接続するので、RDSのセクションでメモしておいた「ホスト名」「データベース名」「管理者ユーザー名」「パスワード」を設定しておく。

## サービスの作成
続いてサービスの作成をします。
先ほど作成したクラスターの詳細を開き、サービスの作成をクリックします。
![スクリーンショット 2020-12-13 14.14.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534248/55928e98-3b63-5d31-1fbb-4037d6e4cb92.png)
サービスの主要項目の設定例を下記に示しておきます。
【機動タイプ】　EC2
【タスク定義】　先ほど作成したタスク定義
【クラスター】　先ほど作成したクラスター
【サービス名】　任意（今回は "effective-work-service" ）
【タスクの数】　1
【クラスターVPC】　先ほど作成したVPC
【サブネット】　先ほど作成した2つのパブリックサブネット
【ロードバランシング】　あらかじめ作成しておいたALB選択（ALBの作成についてはまた別に記事を書きます。）

これで、しばらくしたらコンテナインスタンスが立ち上がり、ALBのDNS名でサービスにアクセスできるようになります。

# さいごに
今回は使ったサービスの中からECSとRDSについてのみ紹介しましたが、他にもS3やRoute53を使って独自ドメインで静的ファイルを配信したり、CircleCIを使って自動CI/CDを設定したりしたので、それらについての記事も書こうと思っています。

最後まで読んでいただきありがとうございました。