React+NestJSアプリをAWSで公開してみる(EC2編)

# はじめに
[いのべこ夏休みアドカレで作成したアプリケーション](https://qiita.com/harimogura/items/d867177e705178d8af06)をクラウドへ公開（デプロイ）してみます。
お決まりですが、目的はデプロイのみであり、他非機能要件に対してクラウドのセットアップ、設定は省いています。
従ってクラウドデプロイのアウトラインレベルであることをお断りしておきます。
また、本方法やコードの一部を用いる場合は自己責任でお願いします。

# 目的
上述の通り、ローカルで開発したアプリをクラウドデプロイします。
開発した時と同じように動作すればOKです。
コンテナイメージの手動デプロイ、プロキシ構築、コンフィグ等
開発したアプリを本番環境で動作させるときのイメージでしょうか？

# 環境
AWSでまずはEC2を使いたいと思います。
プラットフォームは使い慣れているUbuntuを使います。

### 1. 環境構築

#### 1. EC2インスタンス作成
先ずはEC2インスタンスを作成し立ち上げます。
とりあえずSSH接続用の鍵を作成し、インバウンドは22番はマイIP許可、443はALLにしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786643/80fbf2d9-4e9b-7cc2-3998-c32a1c120769.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786643/2ef55ef4-4284-2deb-12ea-948e9109f97b.png)

#### 2. docker(compose)インストール
SSHでEC2へ接続し必要なパッケージをインストールします。Ubuntuなのでaptを使います。

```bash
$ apt moo
                 (__)
                 (oo)
           /------\/
          / |    ||
         *  /\---/\
            ~~   ~~

$ apt update
$ apt upgrade
$ apt install docker
$ apt install docker-compose

$ ~$ docker --version
Docker version 20.10.7, build 20.10.7-0ubuntu1~20.04.1
$ docker-compose -version
docker-compose version 1.25.0, build unknown

```

#### 3. アプリケーション改修
ローカルではVSCode上でReact、NestJSの開発サーバーで起動させていましたが、
AWS上ではDockerイメージを使ってデプロイさせます。
また、各リクエストを受付るリバースプロキシをnginxで構成します。
あとは一応オレオレ証明書を使ってhttps対応します。
今は[無料でいい証明書サービス](https://letsencrypt.org/ja/)がありますのでオレオレ不要かも

```yml:docker-compose.yml
version: "3"

services:
  rev:
    image: sample-app-rev:latest
    container_name: rev
    ports:
      - "443:443"
    depends_on:
      - keycloak
...
```

```config:packages\rev\nginx\templates\default.conf.template

server {
	listen 443;
	ssl on;
	server_name ms-sample-app.com;
	root 		 /var/www/html;
	index 		 index.html index.htm;

	ssl_certificate /etc/pki/tls/certs/server.crt;
	ssl_certificate_key /etc/pki/tls/private/server.key;

	proxy_set_header    Host               $host;
	proxy_set_header    X-Real-IP          $remote_addr;
	proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;
	proxy_set_header    X-Forwarded-Host   $host;
	proxy_set_header    X-Forwarded-Server $host;
	proxy_set_header    X-Forwarded-Port   $server_port;
	proxy_set_header    X-Forwarded-Proto  $scheme;

	location / {
		proxy_pass	http://web:3001;
	}

	location /auth {
		proxy_pass	http://keycloak:8080;
	}

	location /api {
		proxy_pass	http://api:3000;
	}
}

```

#### 4. docker-compose定義作成
各コンテナをdocker-composeを使って定義します。
アプリ、keycloakが利用するDBも定義します。

#### 5. デプロイ
自動化まではしませんが、ローカルでDockerイメージをビルドして、tar.gz形式へセーブ、AWSにscpして
AWS側でイメージをロードしてイメージを反映させます。
（AWSのECRなどは今後使って別記事でまとめたいと思います）

手順としては

```bash
1. Dockerイメージのビルド
docker-compose build

2. タグ付け、save(エクスポート)
docker save sample-app-rev | gzip -c > images/sample-app-rev.tar.gz
...

3. EC2へscpでファイル転送
scp -i "xxxx.pem" images/* user@myec2.compute.amazonaws.com:~/sample-app

4. EC2へSSH接続しDockerイメージのロード(docker load)
ssh -i "xxxx.pem" user@myec2.compute.amazonaws.com
cat sample-app-rev.tar.gz | gzip -d | sudo docker load

5. コンテナ群起動  
$ sudo docker-compose up -d 
```

#### 7. 動作確認
最後に動作確認します。
コンテナが起動していて、httpsでブラウザからアプリが動作していればOK

```bash
$ sudo docker ps
CONTAINER ID   IMAGE                              COMMAND                  CREATED      STATUS         PORTS                                                 NAMES
7774c12a6126   sample-app-rev:latest              "/docker-entrypoint.…"   2 days ago   Up 9 minutes   80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp         rev
84806e8e0caf   sample-app-web:latest              "/docker-entrypoint.…"   2 days ago   Up 9 minutes   80/tcp, 0.0.0.0:49155->3001/tcp, :::49155->3001/tcp   web
d40eb2a98cf5   quay.io/keycloak/keycloak:latest   "/opt/jboss/tools/do…"   2 days ago   Up 9 minutes   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 8443/tcp   keycloak
d16bb66dd269   sample-app-api:latest              "docker-entrypoint.s…"   2 days ago   Up 9 minutes   0.0.0.0:49154->3000/tcp, :::49154->3000/tcp           api
95cd18d0c039   postgres:latest                    "docker-entrypoint.s…"   2 days ago   Up 9 minutes   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp             appdb
f2fb70558718   postgres:latest                    "docker-entrypoint.s…"   2 days ago   Up 9 minutes   0.0.0.0:49153->5432/tcp, :::49153->5432/tcp           keycloakdb
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786643/c0eb4e92-0ca1-9d5e-a7da-3d6cd2072fc7.png)

# さいごに
簡単でしたね。これでサービスが世の中に公開できると考えると素晴らしい！！
もう少しインフラレイヤでの考慮事項（LB、SSL終端・・・）などもありますし、実際のプロジェクト、
業務で構築するには脆弱ですね。ただし、アプリの検証という意味ではこれで十分でした。

LB取り付けてみたり、S3使ってみたりとか色々試してみたいですね。