Dockerコンテナの作成からECSの動的ポート＋ALBでロードバランスするまで【cloudpack大阪ブログ】


# 概要
Dockerコンテナをローカルにつくり、ECRにプッシュ、ECS+ALBでロードバランスするところまでやってみます。

以前はECSをELBでロードバランスする際、EC2ホストとコンテナのポートを静的にマッピングする必要があり、1ホストに1コンテナしか実行できませんでした。ALBで実装された動的ポートマッピング機能を使い、EC2ホストの複数ポートをコンテナのポートと動的にマッピングすることで、1ホストに複数コンテナの環境をロードバランスすることができるようになりました。

環境はこんな感じです。

![Kobito.vF1wI8.png](https://qiita-image-store.s3.amazonaws.com/0/3246/3e153c73-b1fe-ca29-fad1-0a530716f156.png "Kobito.vF1wI8.png")



# 1. コンテナの作成
ローカルでDockerコンテナをビルドし、動かします。

## 環境
Docker for Mac
https://docs.docker.com/docker-for-mac/


Docker for Windows
https://docs.docker.com/docker-for-windows/


## 作成手順

1. Dockerfileを作成
2. コンテナイメージをビルド(docker build)
3. コンテナを起動(docker run)


### Dockerfileを作成

```bash:Dockerfile
FROM centos:latest
RUN yum -y install httpd
ADD index.html /var/www/html
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
```

各行の説明です。

- FROM
  - 基になるDockerイメージを指定します。ここではDockerHubからCentOSのLatestタグが付いているものをPullします。
- RUN
	- コンテナイメージのビルド時に実行されるコマンドです。ここではhttpdをYUMインストールしています。
- ADD
	- コンテナ上に置くファイルの指定です。ローカルの`index.html`をコンテナ上の`/var/www/html`に保存しています。
- CMD
	- コンテナ起動時に実行されるコマンドです。httpdをForegroundで起動しています。


```html:index.html
<h1>Kumoben Test</h1>
```

### コンテナイメージをビルド
```bash:
$ docker build -t kumoben-apache .
```
```bash:
$ docker images                                                                                
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
kumoben-apache      latest              aa1fc4c72c34        2 seconds ago       338.5 MB
centos              latest              180e0e4c79ec        7 weeks ago         196.8 MB
```

### コンテナを起動
```bash:
$ docker run -p 80:80 kumoben-apache
```


# 2. コンテナの保存
ローカルで作成したコンテナイメージをECRにアップロードします。

### マネージメントコンソールでECRリポジトリの作成

リポジトリの作成をクリックします。

![Kobito.ANuLQX.png](https://qiita-image-store.s3.amazonaws.com/0/3246/c6b7b954-64b0-dc6b-ac73-8ee8f3aeabe8.png "Kobito.ANuLQX.png")

リポジトリ名を入力し、次に進みます。

![Kobito.xj02G6.png](https://qiita-image-store.s3.amazonaws.com/0/3246/e161ebed-a559-2a92-baf0-b6ca5a344d75.png "Kobito.xj02G6.png")

ログイン、コンテナのプッシュ方法が表示されます。

![Kobito.a96I97.png](https://qiita-image-store.s3.amazonaws.com/0/3246/339570ed-28d7-b410-52ef-44728e1113f5.png "Kobito.a96I97.png")

### ECRのログイン情報を取得

マネージメントコンソールに表示されたコマンドを実行していきます。

```bash:
$ aws ecr get-login --region ap-northeast-1
```

### ECRにログイン

```bash:
$ docker login -u AWS -p AQE~~~ -e none https://xxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com
Flag --email has been deprecated, will be removed in 1.13.
Login Succeeded
```

### コンテナイメージにECRにアップするためのタグを付与

```bash:
$ docker tag kumoben-apache:latest xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/kumoben-apache:latest
```

```bash:
$ docker images                                                                                
REPOSITORY                                                         TAG                 IMAGE ID            CREATED             SIZE
xxxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/kumoben-apache   latest              23016d00fed9        34 minutes ago      338.5 MB
kumoben-apache                                                     latest              23016d00fed9        34 minutes ago      338.5 MB
centos                                                             latest              980e0e4c79ec        7 weeks ago         196.8 MB
```

### コンテナイメージをECRにプッシュ

```bash:
$ docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/kumoben-apache:latest                       
The push refers to a repository [xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/kumoben-apache]
d72c7de6e1d2: Pushed
a758bd29dbba: Pushed
0aeb287b1ba9: Pushed
latest: digest: sha256:aaaa291c2c781be1f50b12b354e53faa46063a6ee156d0a2c8db76c6 size: 5104
```
![Kobito.5W06VM.png](https://qiita-image-store.s3.amazonaws.com/0/3246/618d69a9-756c-02ef-2c78-4efd7aa95b04.png "Kobito.5W06VM.png")


# 3. コンテナの展開
ECSでコンテナを展開します。

## クラスタを作成

![Kobito.ksUcYa.png](https://qiita-image-store.s3.amazonaws.com/0/3246/9f0a4da3-f47c-6df9-2420-6e93a7d6b374.png "Kobito.ksUcYa.png")

![Kobito.tSxyVV.png](https://qiita-image-store.s3.amazonaws.com/0/3246/75ca33ce-8d1d-eac9-401a-58287e6403b5.png "Kobito.tSxyVV.png")

![Kobito.znDApL.png](https://qiita-image-store.s3.amazonaws.com/0/3246/a10b7ac6-7264-8c88-0e9f-3ee846f93d15.png "Kobito.znDApL.png")

![Kobito.ilgsIz.png](https://qiita-image-store.s3.amazonaws.com/0/3246/9c73871f-ad21-2b53-64dc-cb6913fd82d4.png "Kobito.ilgsIz.png")

### クラスタにコンテナインスタンスを追加

EC2に割り当てるIAMロールを作成します。

`AmazonEC2ContainerServiceforEC2Role`を有効にしたEC2用のIAMロールを作成します。

![Kobito.IaNNAi.png](https://qiita-image-store.s3.amazonaws.com/0/3246/1a1a3bc0-3a01-52e3-0909-93d6aeb9ff05.png "Kobito.IaNNAi.png")

EC2インスタンスを起動します。
ECS用のAmazon Linux(amzn-ami-2016.09.a-amazon-ecs-optimized(ami-c8b016a9))を使用します。
Docker、ECSエージェントがセットアップされていれば、CoreOSやUbuntu等のOSも利用可能です。

![Kobito.X479He.png](https://qiita-image-store.s3.amazonaws.com/0/3246/b5f5e1f6-7e19-4c7c-9617-3a5866aac926.png "Kobito.X479He.png")



ユーザーデータに下記を記載します。
`/etc/ecs/ecs.config`にクラスタ名を記載することで、クラスタに登録されます。

```bash:
#!/bin/bash
echo ECS_CLUSTER=<クラスタ名> >> /etc/ecs/ecs.config
```

![Kobito.YxEI4E.png](https://qiita-image-store.s3.amazonaws.com/0/3246/307f6171-6ca7-4f48-6285-3795df374a58.png "Kobito.YxEI4E.png")


マネージメントコンソールで登録されていることを確認します。

![Kobito.yGmbOc.png](https://qiita-image-store.s3.amazonaws.com/0/3246/8b9947b8-c5d6-13ef-b4c5-05268d9538e2.png "Kobito.yGmbOc.png")


## タスク定義を作成
コンテナの実行方法(タスク)を設定します。

`新しいタスクの定義`をクリックします。

![Kobito.KZCv7a.png](https://qiita-image-store.s3.amazonaws.com/0/3246/38a95228-6795-6707-5c78-b605c07e4258.png "Kobito.KZCv7a.png")

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

![Kobito.gneEsT.png](https://qiita-image-store.s3.amazonaws.com/0/3246/b0d2b78c-8b3d-5864-3c3e-309acd42fb1e.png "Kobito.gneEsT.png")

下記を入力します。

- コンテナ名
	- 任意の名前
- イメージ
	- ECR上のパス
- メモリ制限
	- コンテナに割り当てるメモリ量
- ポートマッピング
	- 紐付けを行うEC2ホストのポートと、コンテナ側のポートを指定します。ホストポートを`0`にすることで、エフェメラルポートが動的に割り当てられます。

![Kobito.41a7vr.png](https://qiita-image-store.s3.amazonaws.com/0/3246/d3726f63-6462-7a84-796c-ba1b7bce6fdf.png "Kobito.41a7vr.png")

![Kobito.VlYmUg.png](https://qiita-image-store.s3.amazonaws.com/0/3246/3f0e0f54-e6f2-566c-224d-9a2230f4570e.png "Kobito.VlYmUg.png")



## サービスを作成

作成したタスク定義からサービスを作成し、コンテナの稼働状況を定義します。

### ALBの作成

ロードバランサもサービスで定義する必要がなるので、先にALBを作成します。

![Kobito.5wS1wl.png](https://qiita-image-store.s3.amazonaws.com/0/3246/cacf0072-c29f-66c3-a6c4-8b24022cbad9.png "Kobito.5wS1wl.png")

`ターゲットの登録`でインスタンスの登録は行いません。

![Kobito.PV9G4c.png](https://qiita-image-store.s3.amazonaws.com/0/3246/e1838291-7521-d51b-8652-c81480e650fe.png "Kobito.PV9G4c.png")

### ECSサービス用のIAMロールを作成

ロールタイプで`Amazon EC2 Container Service Role`を選択します。
ポリシーもそのまま`AmazonEC2ContainerServiceRole`をアタッチします。
![Kobito.ivgTfU.png](https://qiita-image-store.s3.amazonaws.com/0/3246/247d7c76-2d55-023f-f93d-b614acf679a7.png "Kobito.ivgTfU.png")

### サービスの作成

クラスターの画面から`サービス`タブを選択し、`作成`をクリックします。

![Kobito.DhkUSX.png](https://qiita-image-store.s3.amazonaws.com/0/3246/de903c28-7575-f208-ff81-9917e2f39837.png "Kobito.DhkUSX.png")

`サービス名`と`タスクの数`を入力します。
`タスクの数`で指定した数のタスクが常時稼働することになります。
ここでは`4`としています。

![Kobito.us6zW3.png](https://qiita-image-store.s3.amazonaws.com/0/3246/cb1c0ef2-2811-9c09-f8cc-9218773c905d.png "Kobito.us6zW3.png")

`ELBの設定`をクリックし、作成したIAMロール、ELB名を選択し、`コンテナの選択`でタスク定義で設定したコンテナを選択し、`ELBへの追加`をクリックします。

![Kobito.PkDaCa.png](https://qiita-image-store.s3.amazonaws.com/0/3246/c0345e23-c8b2-c5cc-df6f-dcdece2ac03e.png "Kobito.PkDaCa.png")

`リスナーポート`とALB作成時に設定した`ターゲットグループ名`を選択します。
最後に`作成`をクリックします。

![Kobito.dsITjf.png](https://qiita-image-store.s3.amazonaws.com/0/3246/792fb0c6-4023-b0a1-f408-d3259c0b2604.png "Kobito.dsITjf.png")

![Kobito.0PtT3s.png](https://qiita-image-store.s3.amazonaws.com/0/3246/187639db-6231-49ad-1820-9ac2b3ae4e84.png "Kobito.0PtT3s.png")

サービスの画面に戻ると、タスクが指定した数(4つ)実行されています。

![Kobito.KY73Ok.png](https://qiita-image-store.s3.amazonaws.com/0/3246/3b004a97-79f0-bce8-dde0-1e73cf5e5c14.png "Kobito.KY73Ok.png")

ロードバランシングのターゲットグループを確認すると、ターゲットとして2台のインスタンスに2個ずつのターゲットが追加されています。

![Kobito.RsZg08.png](https://qiita-image-store.s3.amazonaws.com/0/3246/6b61c46c-c737-40a3-7714-3710b71db4a9.png "Kobito.RsZg08.png")



### サービスの確認

サービスとして正常に動作しているかの確認のため、1台のインスタンスを停止してみます。

![Kobito.bYG8rZ.png](https://qiita-image-store.s3.amazonaws.com/0/3246/51afcf77-4454-f1b2-99cc-4ce2e380af3a.png "Kobito.bYG8rZ.png")

新たに同じインスタンスで稼働する2つのターゲットが追加されています。

![Kobito.rDbxNQ.png](https://qiita-image-store.s3.amazonaws.com/0/3246/2adc7c6e-73f1-122e-ac9a-4a7d8a243ea5.png "Kobito.rDbxNQ.png")