AWS ECSでDockerコンテナ管理入門（基本的な使い方、Blue/Green Deployment、AutoScalingなどいろいろ試してみた）

# はじめに

Dockerを本番環境で利用するに当たり、私レベルではDockerのクラスタを管理することはなかなか難しい訳です。凄くめんどくさそうだし。
ということで**AWS ECS(EC2 Container Service)**ですよ。

記事書くまでも無いかなと思ったんですけど**意外と手順がWEBにない**（気がしました）。ということで、今回は社内でハンズオンでもやろうかと思って細かく書いてみました。

こんな感じのシナリオをやってみたいと思います。

1. Dockerのイメージを用意する
2. ECSの使い方の基本
3. コンテナのリリース
4. Blue/Green Deployment
5. AutoScaling/ScaleIn

---

# 前準備：Dockerのイメージを用意する

* DockerhHub上にpush済ですので、そのまま使って動かしてみましょう。
* push済のコンテナは8080で起動しますので80にポートをマッピングして起動します。
 
```
[root@centos7 build_demo_ver1.0]# docker run -itd -p 80:8080 --name demo uzresk/demo:ver1.0
92bda2419bf7285d78f12be5877ae3242b5b13ac14409b3c47d38e2d74a06464
```

* ブラウザでこんな画面がでれば成功です。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/5e83874f-c7b3-8a3b-9cd1-9d0a9ca55543.png)

* リリースのテストをしたかったのでver2.0もpushしてあります。
    * https://hub.docker.com/r/uzresk/demo/tags/

-----

# ECSの使い方の基本

## AWS ECSとはなんなのか？

* 今回は利用手順について書こうと思うので割愛しますが、[AWS Black Belt ECS](http://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-online-seminar-2016-amazon-ec2-container-service)を読むのがよろしいかと思います。

## 構成する順番を抑えよう

* こんな感じの順番で構成していきます。大事なので押さえておきましょう。

1. **クラスタの作成**
    * クラスタを動かすためのEC2インスタンスの設定を行います。具体的にはインスタンスタイプ、インスタンス数、VPC、サブネットの設定になります。
2. **タスク定義**
    * クラスタ上で動かすコンテナの情報を登録します。コンテナイメージのURLやCPU、メモリのハード/ソフト制限、アプリケーションで利用する環境変数の定義などを行います。
3. **ロードバランサの作成**
    * クラスタの上位に位置するロードバランサの設定を行います。スケールアウトやスケールインしてもロードバランサはサービスを見つけ出し配下に組み込むことができます。
4. **サービスの作成**
    * クラスタとサービスを結びつけるのがサービスの役割です。タスクの最少数やAutoScalingの設定を行ったりできます。
    * 1つのクラスタに複数サービスを登録することももちろん可能です。

それではさっそくクラスタの作成からやってみましょう。

## クラスタの作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/274f810e-8fdd-d24b-da5f-3ded8771ea01.png)

ContainerInsightの設定は後からでは追加できませんので必要であればチェックしておきましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/3739c416-a10f-8fb9-70fc-e8ca2e58a9e4.png)


![image](https://qiita-image-store.s3.amazonaws.com/0/57686/d6c6350f-9771-5516-e34c-38b05d01a6af.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/419e48f5-0a8b-70d8-b2ea-957223a9d278.png)


* 正常に作成されると「クラスターの表示」ボタンが押せるようになります。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/12acd826-fdad-91bc-56c1-852397dbc72e.png)


## タスク定義

* 次はタスクの定義です。タスクでは

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/ea7ba237-22db-2f7e-dbd4-cb1c8dfb53a7.png)

* タスク定義名を入力し、「コンテナの追加」をクリックします。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/4e461911-b771-755e-12ab-8fad4d3b9a40.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/7594fe20-5737-ae75-f6f9-559382748c3d.png)


* 作成を押せばタスク定義の作成が完了します。

## ELBの作成

* ELBは以下の設定で作っておきましょう
    * ELB名：app-demo-lb
    * 種類：アプリケーションロードバランサ
    * 2つのAZそれぞれのSubnetを指定
    * セキュリティグループで80/HTTPを通すように設定

* ターゲットグループは以下のようにクラスタで設定したインスタンスIDをそれぞれ登録してください。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/1fe6b0ef-a928-2724-81a9-29a806fd8aa4.png)


## サービスの作成

* クラスターのTOPからdemo-clusterを選択し、サービスタブで「作成」

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/bd6aefa7-b481-228b-4128-9ea915791528.png)

* タスク定義とクラスタ名は自動で埋まりますので、サービス名とタスクの数を設定します。
* 今回はAZにそれぞれコンテナを作りたいので2としました。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/a9203a8a-99e1-bdc9-13bc-ca5a8da19766.png)


* 画面の下の方にあるELBの追加を選択します。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/d8c5ae78-9f78-9274-cc8b-4e4985520994.png)

* ELB名は作成したもの、リスナーポートは80、ターゲットグループ名は作成したものを選択します。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/3b479547-9216-c18e-2630-37a9d8f87ba9.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/84c85d1f-7cb1-4702-8d94-08843a33f928.png)

* 「作成」を押して、サービスの画面をみるとPENDINGになっています。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/5556ecbb-7ef0-e155-1c0d-892216f4999d.png)

* 少し経つとRUNNINGになっている事が確認できると思います。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/38319a95-8a95-8efe-0055-90f1bbdb4721.png)

* ELBのエンドポイント/app/をブラウザで叩くと画面が表示されるはずです。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/8ef2f8ad-ea02-f71c-f884-891a51b1457a.png)

## コンテナを落としてみるとどうなるのか

* タスクの一覧から、タスクを一つ消してみましょう。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/c7df1223-377c-ea27-d88a-ac02ece0834b.png)

* 数十秒後に見てみると別のタスクIDのインスタンスが表示されているはずです。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/563ffe67-f06e-d9b9-f852-3805dd29b1ce.png)

* コンテナが起動する数十秒間の間はアプリケーションロードバランサが生きているタスクの方にうまくルーティングしてくれるのかな？と思ったら「502BadGateway」というエラーが画面に返ってきました。
* ここはALBのヘルスチェックの閾値を短くすることである程度は短くできそうです。
* **ここをさらに短くするには、コンテナ自体を軽くすることと、すぐに起動できるアプリケーションを利用するしかなさそうですね。**

---

# コンテナのリリース

* 新しいコンテナをリリースするには、タスク定義に新しいリビジョンを登録し、サービスを更新することで実現可能です。さっそくやってみましょう。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/4fd79647-18f0-fa82-a3bf-cdc41a864daf.png)

* コンテナのバージョンを2.0にして、新しいリビジョンを登録します。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/e974513a-87a7-1213-e5e0-a82753322cbe.png)

* 追加されたリビジョンを選択し、アクション→サービスの更新を押します。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/d1ff1b1b-2259-06a5-bec3-ab36af5d9da4.png)

* タスク定義に新しいリビジョンが指定されていることを確認して、「サービスの更新」

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/dded7c3a-8e0a-c161-0acd-e49f4bd2b5e4.png)

* サービスの「デプロイ」タブを覗くと、今はVer1.0が2つ動いていることが確認できます。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/fedfd0e0-65e8-8650-6ff9-fe020da002b9.png)

* コンテナを一つ落としてみましょう

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/ebab2cbf-ea4f-f08c-c79f-e7db2131f6c1.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/025558bc-ca1c-f5b8-2247-4cb5ed882656.png)

* 実行中の数がそれぞれ１になり、タスクの一覧からもそれぞれが動いていることがわかりますね。
![image](https://qiita-image-store.s3.amazonaws.com/0/57686/f40beabc-be82-ebfb-3f29-2951b3094449.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/0b5ad0bb-bc4f-cb0c-281f-f4cdd5b8f780.png)

---

# Blue/Green Deployment

* Blue/GreenDeploymentでは新しいリビジョンのアプリ用に、新しいインスタンスを構築して入れ替える必要があります。
* この為のパラメータがサービスのデプロイメントオプションにある最大率（maximumPercent）です。2台の時にこの値を200%にしておくと、4台まで同時に動かしておくことができることを意味します。
* 4台のインスタンス上で動かすにはECSのインスタンス台数を事前に追加しておくか、AutoScalingさせておく必要があります。もしECSインスタンスが2台の状態で4つのコンテナを動かそうとすると以下のようなメッセージがでてしまいます。(ポートかぶってるから上がらないよ。ってことですね）

* さっそくやってみます

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/c0e586d0-efbc-7c83-be29-ee64a50bcbe4.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/00cc5e46-0c43-9259-d6db-b281ad954ffc.png)

* この状態でサービスの更新画面でタスク定義を新しいリビジョンに指定して「サービスの更新」を押してみます。
* おお。4台分のコンテナが起動しましたね。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/027f5e91-a1d2-0045-a814-6e47ea26f64d.png)

* ちょっと経つと(3分ほど？）、古いタスクから削除されていきます・・・・

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/192ebc33-4b95-e268-8961-4d8c16fefb0f.png)

* 最期は新しいタスク定義しか残らなくなりました。自動ですよ。自動。便利ですねー。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/5656e971-7d70-98e1-35b1-9d1969f3ef44.png)

---

# Blue/Green Deployment（動的ポートマッピング）

* さきほどは4台のサーバを起動して2台を入れ替える方法を試してみましたが今度は2台を徐々に入れ替える方法です。
* まずは新たにver1.0のタスク定義を追加してみます。この時にホストのポートを空にして登録してください。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/52b9cbd9-9b0d-51e3-d727-9e170bf2ab25.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/3329949b-fc2c-9890-b600-18785ad4e384.png)

* 2台のECSインスタンスを起動して、リビジョン番号3を起動しておきます

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/579402fd-ad57-c2cb-2e43-af8d7bc24b8d.png)

* ALBで利用するターゲットグループには対象のインスタンスを**登録しないでください**AWSがコンテナ自動でAWSが見つけてくれます。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/9e3b2f0e-69aa-b141-0793-c6cbeda89739.png)

* デプロイしてみます。サービスの設定を開いてタスク定義で[demo-app-task:4]、最大率を200に設定します。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/8ea94303-64d2-6855-27be-582c1efcde27.png)

* 最大率を200にすることで合計で4台同時に起動することができるようになります。4台同時に起動できるのはAWSが勝手にポートをかぶらないように設定してくれるからです。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/abd3505d-790d-c223-2788-dc872499c5d1.png)

* 少し経つと勝手にdemo-app-task:3は消えていきます

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/d76f4aa9-4b5e-94be-ba13-769be0db2e55.png)

---

# AutoScaling/ScaleIn

* 次はオートスケールとスケールインを試してみます。
* 通常のオートスケールではインスタンスだけでしたが、インスタンス上で動くコンテナもスケールする必要があります。
* 今回は2つのインスタンスで2つのコンテナで動いていたものを、負荷をかけることにより4つのインスタンス上に4つのコンテナにスケールアウトさせて、スケールインさせたいと思います。

### サービスのAutoScaling設定

* タスクの最大数を4にして、スケーリングポリシーの追加を押します。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/f9da6840-9012-4214-a66d-ed0559363b66.png)

* スケールアウトポリシーの設定を行います。
* CPU使用率の1分間の平均が20%超えた場合2タスクスケールアウトする設定にしました。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/bb9e09e6-8538-bcb3-a45a-67ac5b35462a.png)

* スケールインポリシーの設定を行います。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/1f390cbf-0aa0-6dbd-66ea-96e766ba1d03.png)

* ポリシーが追加できたら「保存」を押しましょう

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/e0cab917-5ba3-737a-a9fd-77328c16919e.png)

* ポリシーが追加されていることを確認して、「サービスの更新」を押します。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/374341b7-60bf-9b97-524f-7558a5c265ff.png)

* これでサービスの設定はおしまいです。

### ClusterのAutoScaling/ScaleInの設定

* ECSインスタンスのオートスケールのポリシーは、EC2インスタンスのAutoScalingGroupの設定で行います。
* 最大数を4にします。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/8d468dae-fea1-8cae-ff2a-8ae2dcf111cc.png)

* Scaleout/ScaleInのポリシーを設定します。
* サービスの設定と同じく、クラスタのCPU使用率が20%以上だと2台スケールアウトするように設定しました。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/4104af9b-fc52-0f59-dad9-a955af0db7fc.png)

### うごかしてみる

* ECSインスタンス上でCPU使用率を強引に（openssl speed -multi 1)あげてみたのですがうまく動きませんでした。
* ありがちですけどabで負荷をかけてみます。
* abをインストール

```
sudo yum install -y httpd24-tools
```

* 負荷をかける

```
ab -n 100000 -c 100 http://localhost/app/loginForm
```

* CloudWatch Alerm(CPUが20%以上）があがる

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/68bc46cc-3cf9-b410-34fa-515bd5cd7a34.png)

* サービスの必要数が4に変更される

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/5148646f-e0e4-4737-d239-f661687e87d1.png)

* インスタンスがオートスケールする

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/15fc70bc-1003-4041-6083-f08a03d79b76.png)

* タスクが起動する

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/c329a9c1-cb98-a071-46f8-31381dcb2203.png)

* 負荷を解除する

* CloudWatch Alerm(CPUが20%より小さい）があがる

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/78a591d6-7df2-d279-9486-fea6dd63fa75.png)

* 必要数が2に変更される

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/9080b1d5-2648-0c28-fc26-c38dddfb7d95.png)

* コンテナとインスタンスが2ずつに変わる

* ここまでやって思ったんですが、インスタンス→コンテナの順に起動されたんですからコンテナ→インスタンスの順に落としていった方がよさそうですね。それはスケーリングポリシーのクールダウン時間で調整ができそうです。

### ECSインスタンスの起動を待つのか？

* ECSのインスタンスの起動を行った後にコンテナが起動されるので結局時間が掛かってしまいます。負荷の時間が予測されるのであればECSインスタンスを事前に起動しておいた方がECSのスケールアウトが高速にできそうです。
* Dockerのメリットの一つである起動の高速化のメリットを享受するにはこのスケジューリングがキーになりそうですね。

### どのインスタンスがスケールインするのか？

* これは終了保護などの機能を使えばインスタンスだけ残しておくことは可能なようですね
    * [スケールイン時に Auto Scaling がどのインスタンスを終了するかを制御する](http://docs.aws.amazon.com/ja_jp/autoscaling/latest/userguide/as-instance-termination.html)

---

# さいごに

ここまでコンテナ管理のハードルが下がると、今後はアプリケーションをコンテナにして配布するのが普通になってくると思います。
そうなるときのためにDockerについてしっかりと理解し、良い設計を心がけたいものですね