AWS ECS FargateでHello Reactしてみた

この記事は ラクスパートナーズ[Advent Calendar 2023](https://qiita.com/advent-calendar/2023/rakus-partners)の18日目の記事になります。

Dockerでアプリ開発をしていたところ、どうせならデプロイまでやってしまおうと思い立ち、AWS ECS Fargateを使用してデプロイを行ったので手順を備忘録として残します。

今回はcreate-react-appしたプロジェクトとDockerのcomposeファイルは用意したので、ローカルで起動確認した後にAWSにデプロイする手順を辿りたいと思います。

## 前提
- AWSアカウントを所有していること 
[【AWS】AWSアカウントの初期設定で行うべきこと(Qiita)](https://qiita.com/yusuke_blog1026/items/3fdeb381acbd8e5da67c#4-%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E5%90%8D%E3%81%A8%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%AE%E7%A8%AE%E9%A1%9E%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%99%E3%82%8B)
- AWS CLIのインストール・設定が済んでいること
[AWS CLIをインストールする方法(Qiita)](https://qiita.com/ponsuke0531/items/ce951e9f8ced041712cb)
- Dcokerのインストールが済んでいること
[Docker公式](https://www.docker.com/get-started/)

## 準備
今回使用するプロジェクトは事前に準備したので、任意の場所にクローンしてください。

https://github.com/yuta-satoh/practice-app

```
git clone https://github.com/yuta-satoh/practice-app.git
```

クローンしたプロジェクトに移動します。
```
cd ~/tmp/practice-app　（クローンしたファイルへのパス）
```

下記のコマンドを実行してコンテナを立ち上げます。
```
docker compose up
```
このコマンドでコンテナイメージの作成とコンテナの立ち上げを行います。


![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/3c1a8c63-4257-524b-51dd-73fd3ce601e6.png)

しばらくしてこのような表示がされたら、
http://localhost:3000
にアクセスします。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/ea674604-c53d-daba-9cbf-fc0e71b7b845.png)
この画面が表示されればOKです。

Ctrl+Cでプロセスを終了してから、下記コマンドで一旦コンテナイメージごと削除します。
```
docker compose down --rmi all --volumes --remove-orphans
```

コンテナの起動が確認できたのでAWSの環境を準備していきます。


## VPC作成
VPCとは？
> Amazon Virtual Private Cloud (Amazon VPC) を使用すると、論理的に隔離されている定義済みの仮想ネットワーク内で AWS リソースを起動できます。
> 仮想ネットワークは、お客様自身のデータセンターで運用されていた従来のネットワークによく似ていますが、AWS のスケーラブルなインフラストラクチャを使用できるというメリットがあります。
[AWS VPCドキュメント](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/what-is-amazon-vpc.html)

 AWSコンソールにアクセスして、VPCのサービス画面を開きます。
 今回は東京リージョンを使用しています。
 
 ![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/d4207fb2-85a6-dd4f-5694-9531cbd1626f.png)

次にVPCダッシュボードの**お使いのVPC**を押下すると、作成済みのVPCリストが表示されます。
今回は新しく作成するので右上の**VPCを作成**を押下します。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/c90b845e-e39d-3b6c-c0ef-fa06c196f139.png)

VPCの作成方法として、サブネットやルートテーブルの作成などを手動で行うこともできますが、今回は本題ではないので自動で作成してしまいます。
VPCの作成画面で**VPCなど**を選択します。
するとサブネットの構成やルートテーブルなどの作成を自動で行うことができます。
名称は**practice-app**としておきます。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/6eafc2d6-db79-3079-e17c-46e079261906.png)

AZの数などの設定をすることができますが、今回は全てデフォルトのままでいきます。
下までスクロールして**VPCを作成**を押下するとVPCの作成が行われます。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/157a70c5-841a-8744-69d1-e0d46cac5a6d.png)

完了後に再度**お使いのVPC**を開きます。
すると先ほど作成した**practice-app**が追加されています。
VPCの準備は完了です。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/33fe9987-3a38-bc19-bfed-788feadf0f0c.png)

## ECSクラスター作成
次にECSクラスターを作成します。
クラスターとはコンテナ化されたアプリケーションをデプロイ・管理するための環境です。
**Amazon Elastic Container Service**のサービス画面を開きます。

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/58b17e43-2112-1382-29aa-ef55a9ec4d0d.png)

ダッシュボードの**クラスター**を押下すると作成済みのクラスターの一覧が表示されます。
右上の**クラスターの作成**を押下して新しいクラスターを作成します。

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/677206ba-00b7-67e8-a6a4-c57e6948c5d3.png)

クラスター名は**practice-app-cluster**とします。
インフラストラクチャは**AWS Fargate(サーバーレス)** を選択します。
下までスクロールして**作成**を押下します。

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/721a67dd-b207-4f12-7527-7a99705040b4.png)

作成が完了するとクラスターの一覧に**practice-app-cluster**が追加されます。
これでクラスターの作成は完了です。

![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/ce62f67c-26aa-5993-28b8-7f57deac6203.png)

## ECRにDockerイメージをプッシュ
クラスターにコンテナアプリをデプロイする場合、
Dockerイメージを**ECR(Amazon Elastic Container Registry)** にプッシュする必要があります。
ECSダッシュボードの**Amazon ECR**を押下するとECRのサービス画面が開きます。

![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/333acdd0-e5bc-a1d0-b63b-22f1eae01aaf.png)

ECRサービス画面の**使用方法**を押下します。

![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/1fe4035d-92a7-e33d-f751-a89d58d52847.png)

可視性設定は**プライベート**、リポジトリ名は**practice-app-image**とします。
入力したら下までスクロールして**リポジトリを作成**を押下します。

![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/d585376b-7bc9-37e7-9e24-b4c500483263.png)

作成が完了すると**practice-app-image**がリポジトリ一覧に表示されます。

![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/3d7106b0-c8bd-d85b-bb78-ffc49d18e5d4.png)

**practice-app-image**を押下し、リポジトリの詳細画面を開きます。
現在はイメージがありませんのでプッシュしていきます。
**プッシュコマンドの表示**を押下します。

![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/f5a97c9b-d905-35de-e064-0ad48e8a4b22.png)

プッシュコマンドの一覧が表示されるので上から順番に指示に従って、ローカルのCLIで実行していきます。

![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/caaf7599-9d0c-56a3-ff4e-ff08bfc4163c.png)

クローンしたプロジェクトに移動します。
```
cd ~/tmp/practice-app　（クローンしたファイルへのパス）
```

今回はpractice-app内のreact-appのDockerイメージを作成するのでreact-appに移動します。
```
cd react-app
```

1. AWS CLIを使用してDockerクライアントの認証を行います。
認証に完了すると**Login Succeeded** と表示されます。
　　
2. Dockerイメージの作成を行います。
イメージの作成完了後、以下のコマンドを入力します。
    ```
    docker images
    ```
    
    ```
    REPOSITORY           TAG       IMAGE ID       CREATED      SIZE
    practice-app-image   latest    5e05f73c8c3d   4 days ago   1.59GB
    ```
    
    このような表示が出ればイメージの作成が完了です。
　　
3. 次にイメージをECRリポジトリにプッシュするためにタグ付けをします。
タグ付けの作成完了後、以下のコマンドを入力します。
    ```
    docker images
    ```
    ```
    REPOSITORY   　　　TAG       IMAGE ID       CREATED      SIZE
    xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/practice-app-image   latest    5e05f73c8c3d   4 days ago   1.59GB
    practice-app-image                                                     latest    5e05f73c8c3d   4 days ago   1.59GB
    ```
    新たにイメージが作成されていることがわかります。
　　
4. 次に作成したイメージをECRリポジトリにプッシュします。
　　

完了後、プッシュコマンを閉じて更新ボタンを押下するとプッシュしたイメージが表示されます。

![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/b79e2d2c-6bba-7e3a-d1e4-2dc26672ae53.png)

latestを押下して詳細を見ることができます。
URIは次のステップのECSタスク定義で使用します。

![24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/7c343d1b-0538-48e4-e0c8-d87f53a2629a.png)


## ECSタスク定義
ECSタスクの定義を行います。
ECSタスクはECSクラスター内でコンテナを実行するための単位です。
ECSサービス画面を開き、**タスク定義**を押下します。
**新しいタスク定義の作成**を押下し、**新しいタスク定義の作成**を押下します。

![19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/6a5a0a94-579f-e0e1-a264-e5cca419f7c3.png)

タスク定義ファミリーは**practice-app-task**とします。
起動タイプは**AWS Fargate**を選択します。

![20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/a58de781-4a8f-aab8-90b7-d91d2643ad67.png)

タスクサイズは最小でいいので、CPUは**0.25vCPU**、メモリは**0.5GB**を選択します。

![21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/222f2e70-df58-3978-2a0d-81c48964a7be.png)

次にコンテナの設定を行います。
名前は**react-app**とします。
イメージURIはECRにプッシュしたイメージのURIをコピペします。
コンテナポートは**3000**番を指定します。
入力後、下までスクロールして作成を押下します。

![23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/122c65af-b7ba-76e5-3cd2-a8adcce1219d.png)

**正常に作成されたタスク定義**の表示がされればタスク定義完了です。

![25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/93a2b421-9ec4-171a-71cf-a2a79535b5d8.png)

## タスクの実行
タスクの定義ができたので、タスクの実行をしていきます。
ECSのサービス画面から**クラスター**を押下し、クラスターの一覧を表示します。
**practice-app-cluster**を押下し、クラスター詳細を開きます。

![26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/ab4ae51a-b830-b4bc-ed48-46c45293bd56.png)

クラスター詳細のサービスタブを選択し、作成を押下します。

![27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/9049cf2f-7cbd-f271-ffca-de3c47f05b65.png)

コンピューティング設定で**起動タイプ**を選択し、**FARGATE**を選択します。

![28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/3b42e0d9-a134-031f-3f06-efc751c98e2a.png)

タスク定義のファミリーを**practice-app-task**を選択します。
リビジョンはタスクのバージョンを示します。
Dockerイメージの更新等でタスクを更新すると、2、3、4...といった形で増えていきます。
サービス名は**practice-app-service**とします。

![29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/e2e68ded-0a50-406f-546d-b169ca3e3b87.png)

次にネットワーキングの設定を行います。
VPCは先ほど作成した**practice-app-vpc**を選択します。
サブネットはprivate以外を選択してください。

![30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/c2135464-aeab-b366-4b04-1498ca58f752.png)

続いてセキュリティグループの設定をします。
**新しいセキュリティグループの作成**を選択します。
セキュリティグループ名は**practice-app-sg**とし、説明にも同様に入力します。
インバウンドルールとしてタイプは**カスタムTCP**、ポートは**3000**番を開放します。
この3000番は、タスク設定の際にコンテナのポートとして3000番を指定したためです。
ソースは**Anywhere**を選択します。全ての外部アクセスを許可します。
ここまで入力が終了したら、下までスクロールして**作成**を押下します。

![31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/675ff4c7-a402-0485-c231-48e90af65388.png)

サービスの作成には少し時間がかかります。
クラスターの詳細でサービスタブを開いて**更新**を押下し、ステータスがアクティブになったらサービス名を押下してサービス詳細を開きます。

![33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/4e26fdd1-8f3b-40ed-011a-f36ef169e73e.png)

サービス詳細のタスクタブを開くと実行中のタスクが表示されます。
前回のステータスが実行中になっていることを確認してタスク名を押下します。

![34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/82d384ea-20e5-25ff-a944-da3d76bb689f.png)

タスク詳細のネットワーキングタブを押下します。
パブリックIPをコピーして、
http://{パブリックIP}:3000
にアクセスします。

![35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/1e195c92-b43e-7399-c6be-1ad15f295e6c.png)

http://{パブリックIP}:3000にアクセスしてこの画面が表示されたら成功です。

![36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/97f72398-e7b2-4d63-5672-a22fa3038fc4.png)

## 片付け
このままサービスを起動し続けているとコストがかかってしまいますので、きちんと削除しておきましょう。
タスク詳細画面で**停止**を押下し、タスクを停止します。

![37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/2e7a6816-0336-aabf-6916-692e8ce43a23.png)

クラスター詳細画面に戻り、サービス名をチェックして**更新**を押下します。

![38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/0518d4cf-0e00-94fc-3de2-216f8cb7627f.png)

デプロイ設定の必要なタスクを0にして下部にある**更新**を押下します。

![39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/c8476a8c-b771-243d-45e2-e6625f5c224a.png)

サービス名をチェックして**サービスを削除**を押下します。
必要事項を入力して削除完了です。

![40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620134/cf0352c7-f894-eede-df7f-15478f8d83e2.png)


ECRは無料枠がありますが、削除する場合はリポジトリの一覧から削除することができます。
VPCは今回の設定ではコストがかからないので放置でも大丈夫です。


## まとめ
VPCの作成からAWS Fargateを使用したデプロイまでの手順をまとめました。
今回は最低限の環境でのデプロイでしたが、実際にはデータベースとの連携やロードバランシングの設定も必要なので、いつかそちらもまとめたいと思っています。

## おまけ　AWS SAA受験してみた
**勉強期間**
約1ヶ月半

**教材**
* [AWS認定資格試験テキスト　AWS認定ソリューションアーキテクト - アソシエイト　改訂第2版](https://www.amazon.co.jp/AWS%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E8%A9%A6%E9%A8%93%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-AWS%E8%AA%8D%E5%AE%9A%E3%82%BD%E3%83%AA%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%88-%E3%82%A2%E3%82%BD%E3%82%B7%E3%82%A8%E3%82%A4%E3%83%88-%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88-%E4%BD%90%E3%80%85%E6%9C%A8-%E6%8B%93%E9%83%8E-ebook/dp/B08MVXRFFN/ref=tmm_kin_swatch_0?tag=maftracking348119-22&linkCode=ure&creative=6339&_encoding=UTF8&qid=1611081155&sr=1-1)
辞書代わりに使っていた。索引ページでAWS〜のサービスが全て一箇所にまとまっているのでそこだけ使い辛かった。
　
* [【SAA-C03版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（6回分390問）](https://www.udemy.com/course/aws-knan/)
定価7600円は高いが、セールの時を見計らって買うと2000円くらいになる。
6回分の模擬試験（1回は旧版の試験）が入っている。新版の試験を１つ直前用に残しておいて周回した。本番よりも難しい感じがしたので効果的だと思う。


**結果...無事合格！**
問題集の周回も効果的だったが、一番効果的なのは実際にサービスを触ってみること。
次の目標はSOA。