VPC + EC2 + Docker でアプリケーションをデプロイする。

# はじめに
2019/08/08に開催されたAWSハンズオンの資料を元に、NuxtアプリをAWSを使ってデプロイすることがあったので備忘録的にまとめておきます。
今回初めてAWSに触ったので間違いがあるかもしれませんが、その時は助言をいただけるとありがたいです。
また、今回は例としてNuxtアプリをAWS環境にデプロイすることを目標としています。

# 対象読者
* AWSの基本を学習したい方（AWSアカウントは持っている）

# 全体構造
こんな感じです。

![Qiita AWS構成図-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/d18cf111-d8d1-6b8b-a36c-8511ffde78b7.png)



難しそうに見えますが、一つ一つ見てみたらとてもわかりやすいですので、少しずつみてみましょう。

# VPC
## VPCとは
**VPC**とは **Amazon Web Service Virtual Private Cloud** の略称で、プライベートな仮想クラウド環境を提供するサービスのことです。このうえに仮想サーバーである**EC2**（あとで説明します）やデータベースを立てたりして使います。

## VPCの作成
まずはAWSのトップ画面の『**サービスを検索する**』から『**VPC**』を選択。
![スクリーンショット 2020-11-08 22.32.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/1130f4d6-668d-4537-0980-e79ef49976e8.png)
『**VPCウィザードの起動**』を押下。
![スクリーンショット 2020-11-08 22.34.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/9df60d5d-9458-3739-4818-ad8293767563.png)
**※VPCウィザードとは**
**VPCウィザード**とは、**VPC**と**NATインスタンス**を簡単に作成する機能のことです。
**VPC**には、**パブリックサブネット**というインターネットからアクセスできる部分と、**プライベートサブネット**というインターネットから直接アクセスできない部分都に分かれています。
**NATインスタンス**とは、簡単にいうとプライベートサブネットとパブリックサブネットを繋ぐものみたいなニュアンスでいいと思います。僕も詳しくはわかりません。詳しくは[公式](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_NAT_Instance.html)読んでください。

『**選択**』を押下。
![スクリーンショット 2020-11-08 22.49.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/9a8722e1-3714-47ff-140c-52b5ce49e12f.png)

それぞれ以下のように記入して『**VPCの作成**』を押下。
![スクリーンショット 2020-11-08 22.50.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/9c336e71-af76-b40e-59b3-f51ddec20ff9.png)
**※アベイラリティゾーン(AZ)とは**
**AZ**とは、選択したリージョンの中にある物理的なサーバーを管理している施設群（データセンター）のことです。
**ELB**（今回説明はしません）を用いて複数の**AZ**を使用することで、何かしらの障害が起きた時に、サーバーがダウンしても継続してサービスが提供できるようにすることができます。


『**OK**』を押下
![スクリーンショット 2020-11-08 22.50.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/2cc30eab-bfd5-8062-64e5-91b447c7fbd0.png)
以下のように表示されていれば作成成功です。
![スクリーンショット 2020-11-10 13.12.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/e62b50e6-ef43-18af-fa57-4554d2025fe0.png)
一応サブネットもみてみます。
左のメニューから『**サブネット**』を選択。
先ほど作成した、サブネット（今回は、『Qiita-パブリックサブネット-1a』）にチェックをいれる。
アベイラリティゾーンが『ap-northeast-1a (apne1-az4)』IPv4が『10.0.0.0/24』になっているか確認。
![スクリーンショット 2020-11-10 13.17.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/46a0e275-e61d-d0c9-bcf5-ce32bf5a9ab7.png)
『**ルートテーブル**』を押下。
デフォルト(0.0.0.0/0)のルートが**インターネットゲートウェイ（igw-xxx...）**に向いていることを確認する。
![スクリーンショット 2020-11-10 13.33.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/a01992f4-1756-7870-7289-1524deae0289.png)
**※インターネットゲートウェイ（IGW）とは**
**VPC**内に作成された**サブネット**が外部と接続（グローバルIPに接続）できるようにする機能。


## ルートテーブルの設定
[この記事](https://qiita.com/chro96/items/21863e0960ba4ac72470#:~:text=%E3%82%B5%E3%83%96%E3%83%8D%E3%83%83%E3%83%88%E5%86%85%E3%81%AB%E3%81%82%E3%82%8B%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9,%E9%80%81%E3%82%89%E3%81%AA%E3%81%84%E3%81%AE%E3%81%A7%E3%80%81%E9%80%9A%E4%BF%A1%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82)によると、
**ルートテーブル**とは、
>サブネット内にあるインスタンス等がどこに通信にいくかのルールを定めたものです。つまり、ルートテーブルはパケットの宛先(IPアドレス)を見て、どこに通信を流すかが書かれている表です。この表をみてパケットを運ぶので、表にない宛先のものはパケットを送らないので、通信できません。サブネット毎にどこに通信ができるかを定めたものだというところがポイントです。

とのことです。

今回はまだルートテーブルを設定できていないので、これを設定していきます。

『**VPC**』のメニューから『**ルートテーブル**』を選択。
今回使用する**VPC ID**を持つ**ルートテーブル**を選択して、『**ルート**』の中にある『**ルートの編集**』を押下。
![スクリーンショット 2020-11-10 15.52.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/9b2d564a-0b08-b84f-69fc-9f76bc9ddb4e.png)

『**ルートの追加**』を押下。
その後、『**送信先**』を『0.0.0.0/0』、『**ターゲット**』を『**Internet GateWay** → **igw-xxx.....**』を選択。
その後、『**ルートの保存**』を押下。
![スクリーンショット 2020-11-10 16.07.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/43d1fc8b-f43d-6195-9a4f-28d3a290c339.png)

『**サブネットの関連付け**』から『**サブネットの関連付けの編集**』を押下。
![スクリーンショット 2020-11-10 16.12.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/e4d59cd1-ecb5-553e-851c-e45bc67b6c45.png)

今回使用する**サブネット**を選択して、『**保存**』を押下。

![スクリーンショット 2020-11-10 16.13.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/97e318d7-cdf1-88c6-1c7d-bf8e6eb07855.png)


## VPC作成結果
ここまでで以下のように設計することができました。
![Qiita AWS構成図-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/fb2278dc-516f-a9da-3107-2af5b8e4d9f6.png)

# EC2
## EC2とは
**EC2**とは、**Amazon Elastic Compute Cloud**の略称で、仮想サーバーを構築するサービスのことです。
OSやスペック等を自分の裁量で自由に決めることができるため、冗長的なサービスの実現ができます。

## EC2の作成
まずはAWSのトップ画面の『**サービスを選択する**』から『**EC2**』を選択。
![スクリーンショット 2020-11-10 15.01.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/35ef3eb2-452b-b53f-ab47-f29a8f07c741.png)

『**インスタンスを起動**』を押下。
![スクリーンショット 2020-11-10 15.03.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/ddf576fe-9a8c-4ff5-ef7f-f985d3e5b1de.png)

今回は『**Amazon Linux 2 AMI ....**』の『**選択**』を押下。
![スクリーンショット 2020-11-10 15.04.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/9d344cdc-d8fc-883e-ce08-50536f434917.png)

今回は『**t2.micro**』を選択したのち、『**次のステップ：インスタンスの詳細の設定**』を押下。
![スクリーンショット 2020-11-10 15.06.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/fd4ad365-6776-21b3-4aa8-d225c7e52f85.png)

先ほど作成した**VPC**, **サブネット**を選択して『**自動割り当てパブリックIP**』を『**有効**』に変更。
その後、『**次のステップ：ストレージの追加**』を押下。
![スクリーンショット 2020-11-10 15.17.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/e8e89f57-5551-848f-db18-44d19aa2a2ba.png)

そのまま『**次のステップ：タグの追加**』を押下。
![スクリーンショット 2020-11-10 15.20.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/856e52d9-bc26-14b4-16fa-a164f1a98f01.png)

そのまま『**次のステップ：セキュリティグループの設定**』を押下。
![スクリーンショット 2020-11-10 15.21.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/05861e8a-e537-245b-335c-1bc2466a697d.png)

『**ルールの追加**』を押下したあとに、『**カスタムTCP**』『**3000**』『**0.0.0.0/0**』をそれぞれ選択。
その後、『**確認と作成**』を押下。
![スクリーンショット 2020-11-10 15.23.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/7d097223-bccd-1f53-ae84-dc3aa1fe8f40.png)

そのまま『**起動**』を押下。
![スクリーンショット 2020-11-10 15.26.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/6074a350-c935-ea5a-ab0f-a633a7b67b84.png)

『**新しいキーペアの作成**』を選択し、『**キーペア名**』を記入（今回は『**Qiita-example**』）、『**キーペアのダウンロード**』を押下して、キーペアを自分の好きな場所で保存する。そのあと、『**インスタンスの作成**』を押下。
![スクリーンショット 2020-11-10 15.26.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/de635acd-ef89-8dea-1aff-f8215fdc2632.png)
**キーペア**はあとで使用するので、必ず自分のわかるところに保存しておいてください。

『**インスタンスの表示**』を押下。
![スクリーンショット 2020-11-10 15.33.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/8200a897-e094-8313-cc1c-81d11ea5f100.png)

このように表示されれば作成が完了です。
画像赤枠の部分を押下すると名前が変更できるため、一応変更しておきましょう。
![スクリーンショット 2020-11-10 15.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/325324cf-2d17-3ee1-0670-505c7e249dac.png)

## EC2作成結果
ここまでで以下のように設計することができました。
![Qiita AWS構成図-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/8abd1105-6428-6bab-2961-306413d42c07.png)


# デプロイ
いよいよNuxtアプリをデプロイしていきます。
[この記事](https://qiita.com/TakumaKurosawa/items/e67315583009257cd1ea#ec2%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%ABssh%E6%8E%A5%E7%B6%9A%E3%81%97%E3%82%88%E3%81%86)が非常にわかりやすかったので、こちらを元に行っていきます。

## ssh接続
『**EC2**』のメニューから『**インスタンス**』を選択。
**インスタンス**の一覧から、自分の**インスタンス**を選択。
下のメニューのうち、『**パブリック IPv4アドレス**』の値をコピー。
![スクリーンショット 2020-11-10 16.20.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/6c7a3fa4-fcb6-9096-d55d-31764d5d3396.png)

ターミナルを起動して以下のコマンドを入力

```
# ダウンロードしたaws-tutorial.pemがあるディレクトリへ移動
$ cd ~/ペアキーを保存した場所

# pemファイルを~/.sshへ移動
$ mv Qiita-example.pem ~/.ssh

# pemファイルにアクセス権限を付与しておく
$ chmod 400 ~/.ssh/Qiita-example.pem

# ssh接続
$ ssh -i "~/.ssh/Qiita-example.pem" ec2-user@[さっきコピーしたIPアドレス（ペースト）]
Are you sure you want to continue connecting (yes/no)? yesと入力
```

成功すると、以下のような画面が表示されます。

```

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
8 package(s) needed for security, out of 17 available
Run "sudo yum update" to apply all updates.
[ec2-user@ip-****** ~]$
```
これでSSH接続は完了です。
Linuxインスタンス内でコマンドを行うことができるようになったところで、必要なパッケージをインストールしていきます。

```
# yumをアップデート
$ sudo yum update -y

# Gitのインストール
$ sudo yum install git -y

# Dockerのインストール
$ sudo yum install -y docker

# Dockerの起動
$ sudo service docker start
$ sudo systemctl enable docker.service
$ sudo service docker status

# 下記のような出力結果が得られればOK
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since 日 2019-12-22 03:26:02 UTC; 10s ago
     Docs: https://docs.docker.com
 Main PID: 12952 (dockerd)
   CGroup: /system.slice/docker.service
           └─12952 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd....

# dockerコマンドを使用可能にする
$ sudo usermod -a -G docker ec2-user

# 一度exit
$ exit

# もう一度ssh接続
# スーパーユーザに切り替える
$ sudo -i

# 必要なファイルをダウンロード
curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 権限を与える
chmod +x /usr/local/bin/docker-compose

# 通常ユーザに戻る
exit
```

これでGitもDockerも動くようになったので、早速自分のリポジトリからデプロイしたいプロジェクトを選択していきます。今回はNuxtアプリをクローンしてきたと仮定します。

もう一度ssh接続して、

```
git clone [自分のGitリポジトリのURL]

cd [クローンしてきたプロジェクト]

docker-compose up
```

これでデプロイは成功です。


```
http://[VPCのパブリックIPv4アドレス]:3000
```
にアクセスすると自分のアプリの画面が表示されると思います。
![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_317034_057c6c11-24a7-42e6-ae7c-ca6490478ff9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412378/6ab49b89-07b8-2695-2392-21897fea1ab5.png)

お疲れ様でした。


**ELB**も組み込んだ構築は[こちら](https://qiita.com/sychocola1/items/12680b19d118a550b8a9)をご覧ください。


# 参考資料
* [AWS Hands-on for Beginners 〜 スケーラブルウェブサイト構築編 〜](https://pages.awscloud.com/event_JAPAN_Hands-on-for-Beginners-Scalable_LP.html?trk=aws_introduction_page)
* [【AWSハンズオン】Nuxt + Golang構成のWebアプリをAWSへデプロイしよう！](https://qiita.com/TakumaKurosawa/items/e67315583009257cd1ea#git%E3%81%A8docker%E3%82%92%E5%8B%95%E3%81%8B%E3%81%9B%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%97%E3%82%88%E3%81%86)