[AWS] Amazon ECS(EC2タイプ)のちょっと長めのチュートリアル(第3回)

※本記事は [Amazon ECS(EC2タイプ)のちょっと長めのチュートリアル(第1回)](https://qiita.com/VA_nakatsu/items/c8a4b24b8cffd0e9047b) および [(第2回)](https://qiita.com/VA_nakatsu/private/555d75cd8a7ff8584eaf) の続きです。

前回までで、ECSクラスターが作成できました。今回はサービスとタスクを作成して、Dockerコンテナが起動されることを確認します。

<font color="red">注：このチュートリアルでは前回同様に、[ELB 1台](https://aws.amazon.com/jp/elasticloadbalancing/pricing/) と、[t3.microのEC2 2台](https://aws.amazon.com/jp/ec2/pricing/) のAWS利用料が発生します。</font>

# サービス、タスクとは

毎回使っている簡単な方の図：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/baf1065f-ee1c-f44c-02fe-62ebb1c7d0d2.png)

これから残りのサービスとタスクを作成していくわけですが、正確には"タスク定義"というものを先に作成するため、

- <font color="blue">タスク定義(Task Definition)</font>：1つ以上のコンテナ設定が記述されたJSONファイル、具体的には以下のような設定を記述します。
    - 実行するDocker(ECR)イメージ
    - Docker起動オプション(環境変数/マウントポイント/ログ設定/ヘルスチェックなど)
    - IAMロール
    - ネットワークモード
    - CPU/メモリの制限
- <font color="blue">サービス(Service)</font>：定義されたタスクを、ECSクラスターで動作させるための設定
    - クラスターと、起動させるタスクの数
    - デプロイ設定
    - インスタンス配置設定
    - VPC、ロードバランサ設定
- <font color="blue">タスク(Task)</font>：サービスによって、実際に実行されたコンテナ(群)。今回の例では1タスク＝1 Dockerイメージで起動されます。

の順で作成していきます。ざっくり言うと、<b><font color="blue">タスクの方がコンテナの起動設定</font></b><font color="blue">(多くがDockerのパラメタで指定可能なもの)</font>で、<b><font color="blue">サービスの方がAWS環境の設定</font></b>となります。

タスク定義は図で表現されることはほとんどありませんが、実際の設定の多くはここにあります。(慣れると気にならなくなりますが、サービスの方にもサービス定義があった方が分かりやすいんじゃないかと最初は思いました。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/3d9f7887-129b-4275-141a-c51af1d90e46.png)

難しい方の図。ようやく [第1回](https://qiita.com/VA_nakatsu/items/c8a4b24b8cffd0e9047b) で作成したコンテナの動作確認ができるようになります。

# インスタンスを起動

まず、[前回](https://qiita.com/VA_nakatsu/private/555d75cd8a7ff8584eaf) EC2の課金が発生しないようインスタンス数を0にしておいたのを、戻します。
ECSクラスターの設定から「ECSインスタンス」タブ→「ECSインスタンスのスケール」で台数を2に設定しておきます。
![100.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/721ecbcc-1a92-87a0-d5ac-eae755b9b619.png)

# 4) タスク定義の作成

ECSのメニューから、「タスク定義」→「新しいタスク定義の作成」を選択します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/508023c3-cd52-f08c-d21a-3bb431e4db56.png)|
|:-:|

起動タイプでEC2を選択して次のステップに進みます。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/a41162bc-1b64-1f9f-5fbc-37b59c41022d.png)|
|:-:|

「タスクとコンテナ定義の設定」で必要な情報を入力します。
- タスク定義名 : 任意の名前
- タスクロール : 前回作成した <b><font color="blue">タスク用ロール</font></b> を指定
- ネットワークモード ： " `<default>` " を選択

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/042bfa43-0b31-fbb8-1b2f-7b0bb5bde29d.png)|
|:-:|

次に、EC2インスタンスのストレージをコンテナにマウントする設定を追加します(テスト用コンテナの動作に必要ありませんが説明のため)。
画面の下（縦長の画面なので一番下までスクロールします）にある「ボリュームの追加」を選択します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/b697470e-a00f-83c6-3798-d1a574792927.png)|
|:-:|

「ソースパス」がEC2インスタンスのパスになります。ここでは `/tmp/ecsdemo` を指定しています。
![a001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/78c278a4-e1f8-ac19-0f72-cbb504f80fdc.png)

「追加」を押すと元の設定画面に戻り、設定が追加されたことが確認できます。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/08ba05c3-d780-6ac6-cb6f-85c03c6ae714.png)|
|:-:|

次に、画面を少し上に戻って、コンテナ定義の項目で「コンテナの追加」ボタンを押します。

|![a002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/0bbc6add-af2a-59e9-7f94-5f4c66c21be3.png)|
|:-:|

必要な情報を入力します。
- コンテナ名 : 任意の名前
- イメージ : 第1回で作成したECRイメージのパス（AWSアカウント名からダグまで含むフルパスを設定します）
- メモリ制限 ： 128
- ポートマッピング：ホストポート8080、コンテナポート80

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/365db54d-8731-7427-e726-7ab479654059.png)|
|:-:|

入力画面を下に進み、環境変数を設定します(これもテスト用コンテナの動作に必要ありませんが説明のため)。ここでは `TEST_ENV01` という変数を設定しています。ここの画面が少し分かりづらいですが、キーと値の間にある"Value"というプルダウンも明示的に選択する必要があるので注意して下さい。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/b5bd3bf0-343d-ae5b-8438-e94011c7c1de.png)|
|:-:|


最後に「ストレージとログ」で、マウントポイントを設定します。
こちらはコンテナ内のパスで、例として `/mnt/host_dir` というディレクトリを指定しています（事前に存在しなくても構いません）。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/f6af650c-9311-48a3-a92f-360344ab26d4.png)|
|:-:|

「追加」ボタンを押してタスク定義の作成画面に戻り、そこで「作成」を押してタスク定義の作成は完了となります。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/eecee709-85e5-35bf-3861-7fb5e3422e12.png)|
|:-:|

# 5) サービスの作成

サービスはECSクラスターの「サービス」タブから「作成」を選択します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/4753cb06-1879-7872-54a5-abd168a14fec.png)|
|:-:|

サービスの設定画面で必要な情報を入力します。
- 起動タイプ : EC2
- タスク定義 :  4)で作成したタスク定義
- クラスター ： 前回作成したクラスター
- サービス名 ： 任意の名前
- タスクの数 ： 2
その他の設定はデフォルトでOKです。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/becdf34f-efb4-8e4f-1f25-fe8013ca019d.png)|
|:-:|

次に進み、ALBの設定を行います。
- ELBタイプ ： "Application Load Balancer"を選択
- サービス用のIAMロールの選択 ： "AWSServiceRoleForECS"(デフォルト)
- ELB名 ： 前回作成したELB を選択
をそれぞれ選択します。続いて下にある「負荷分散コンテナ」で、先ほど作成したコンテナが表示されていることを確認して「ELBへの追加」を押します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/84b87499-d854-075e-7e98-d05602f7e04e.png)|
|:-:|

負荷分散コンテナの設定を入力します。
- リスナーポート ： 8080:HTTP
- ターゲットグループ名 ： 新規作成を選択し、任意の名前を入力
- ターゲットグループのプロトコル ： HTTP
- パスパターン ： `/*` (スラッシュとアスタリスク)を入力
- 評価値 ： 1
- ヘルスチェックパス ： `/index.html` 

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/51b0b950-9e87-04cf-b94d-42e17a69547f.png)|
|:-:|

画面下に進み、サービスの検出オプションは外して次のステップに進みます。

|![a003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/ffa88a3e-b844-20ae-ba17-d248cd8fffde.png)|
|:-:|

Auto Schaingオプションはデフォルトのまま
次のステップに進みます。

|![a004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/022e68ce-7557-7f45-d106-a5a45f9e1a92.png)|
|:-:|

最後に確認画面で「サービスの作成」を押します。

|![a005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/d835ed3a-5aa2-b06a-b735-0a770084f8f5.png)|
|:-:|


サービスが作成されたら「サービスの表示」ボタンを押します。

|![a006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/ee79afd0-c349-a1c4-23e1-b144170630fd.png)|
|:-:|

クラスターの画面に遷移し、(サービスではなく)「タスク」タブが表示されます。2つのインスタンスで、それぞれタスクが起動していれば作成は完了となります。

|![101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/c4041ab6-e131-258e-a2ec-7d0be1f3a375.png)|
|:-:|

# 動作確認：ブラウザでの確認

ようやくこの構成ができたので、ブラウザでnginxのテストページにアクセスしてみます。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/d2da5036-6010-f3ac-645e-6dceaa22cde5.png)|
|:-:|

EC2 → ロードバランサから ELBのDNS名 を確認し、 `http://<ELBのDNS名>:8080/index.html` にアクセスします。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/fc0c7296-4a26-259f-7a62-738aef0a4045.png)|
|:-:|

次に、テスト用に追加したhtmlが表示されることを確認します。 `http://<ELBのDNS名>:8080/demo.html` にアクセスします。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/912be371-08fb-789d-8902-d64f3d3a04c1.png)|
|:-:|

うまく接続できない場合は、第2回で作成した <b><font color="blue">ELB用セキュリティグループ</font></b> の設定をまず確認して下さい。マイIPに限定して作成してあったので、お使いのネットワーク環境によってはアクセス元をもう少し広く設定する必要があるかもしれません。

# 動作確認：EC2にログインして確認してみる

EC2タイプなので、ログインして確認することが可能です。前回作成した鍵を使って、ECSインスタンスにsshでログインして確認します。

```console
※Dockerプロセスの確認※
# docker ps
CONTAINER ID    IMAGE                                                                       COMMAND                  CREATED             STATUS              PORTS                  NAMES
5aa208dd78ff    <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-demo01:latest   "nginx -g 'daemon of…"   40 minutes ago      Up 40 minutes       0.0.0.0:8080->80/tcp   ecs-va-ecs-task-definition01-1-nginx-demo01-faa6d1db8188b2ae4900
1aa15ba1a11f    amazon/amazon-ecs-agent:latest                                              "/agent"                 2 hours ago         Up 2 hours                                 ecs-agent

※テスト用のコンテナにログイン※
# docker exec -it 5aa208dd78ff /bin/bash

※環境変数が設定されていることの確認※
root@5aa208dd78ff:/# export | grep TEST_ENV01
declare -x TEST_ENV01="This_is_test"

※マウントポイントを確認するため、ファイルを作成※
root@5aa208dd78ff:/# ls -l /mnt/host_dir/
total 0

root@5aa208dd78ff:/# export > /mnt/host_dir/container_export.txt

root@5aa208dd78ff:/# ls -l /mnt/host_dir/container_export.txt
-rw-r--r-- 1 root root 599 Jul  2 07:51 /mnt/host_dir/container_export.txt

root@5aa208dd78ff:/# cat /mnt/host_dir/container_export.txt
declare -x AWS_CONTAINER_CREDENTIALS_RELATIVE_URI="/v2/credentials/221a631f-ecee-4ec0-8539-921f512c0efa"
declare -x AWS_EXECUTION_ENV="AWS_ECS_EC2"
declare -x ECS_CONTAINER_METADATA_URI="http://169.254.170.2/v3/5c8ca5e4-8043-4aad-ba1f-aca76518f101"
declare -x HOME="/root"
declare -x HOSTNAME="5aa208dd78ff"
declare -x NGINX_VERSION="1.13.1-1~stretch"
declare -x NJS_VERSION="1.13.1.0.1.10-1~stretch"
declare -x OLDPWD
declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
declare -x PWD="/"
declare -x SHLVL="1"
declare -x TERM="xterm"
declare -x TEST_ENV01="This_is_test"

※ホストOSに戻る※
root@5aa208dd78ff:/# exit
exit

※マウントポイントにコンテナで作成したファイルがあることを確認※
# ls -l /tmp/ecsdemo/
total 4
-rw-r--r-- 1 root root 599 Jul  2 07:51 container_export.txt

# cat /tmp/ecsdemo/container_export.txt
declare -x AWS_CONTAINER_CREDENTIALS_RELATIVE_URI="/v2/credentials/221a631f-ecee-4ec0-8539-921f512c0efa"
declare -x AWS_EXECUTION_ENV="AWS_ECS_EC2"
declare -x ECS_CONTAINER_METADATA_URI="http://169.254.170.2/v3/5c8ca5e4-8043-4aad-ba1f-aca76518f101"
declare -x HOME="/root"
declare -x HOSTNAME="5aa208dd78ff"
declare -x NGINX_VERSION="1.13.1-1~stretch"
declare -x NJS_VERSION="1.13.1.0.1.10-1~stretch"
declare -x OLDPWD
declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
declare -x PWD="/"
declare -x SHLVL="1"
declare -x TERM="xterm"
declare -x TEST_ENV01="This_is_test"

※イメージの確認※
# docker images
REPOSITORY                                                           TAG      IMAGE ID       CREATED       SIZE
<AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-demo01   latest   de6344632e81   2 weeks ago   109MB
amazon/amazon-ecs-agent                                              latest   267bac512a39   3 weeks ago   57.1MB
amazon/amazon-ecs-pause                                              0.1.0    54d8403124ce   3 weeks ago   954kB
```

# スケールインしておく

以上で、一通りの構築作業は完了しました。次回以降コンテナの更新処理や異常系を試す予定ですが、それまではインスタンス費用がからないよう台数をまた0にしておきます。

これまでのようにインスタンス台数を減らすだけで課金は発生しませんが、それではタスクの再起動が繰り返されることになるので、まずタスクの数を0に設定します。サービスの設定で「更新」を選択します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/bf47e728-cf4c-7656-0ccb-112b924ad755.png)|
|:-:|

タスクの数を0に変更して更新します。

|![a008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/d3e27525-b8b3-3441-c97b-29285dabb5b7.png)|
|:-:|

その後、クラスターの設定からインスタンスを0に変更します。
![102.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/01230cf3-1d12-a9e4-b078-be89af08e53c.png)

# Link

- [Amazon ECS(EC2タイプ)のちょっと長めのチュートリアル(第1回)](https://qiita.com/VA_nakatsu/items/c8a4b24b8cffd0e9047b)
- [Amazon ECS(EC2タイプ)のちょっと長めのチュートリアル(第2回)](https://qiita.com/VA_nakatsu/private/555d75cd8a7ff8584eaf)

# 参考資料

- [A beginner’s guide to Amazon’s Elastic Container Service](https://www.freecodecamp.org/news/amazon-ecs-terms-and-architecture-807d8c4960fd/)