Amazon ECS が Docker  Volumes をサポートしたのでやってみる

## はじめに
Amazon ECS が ~~やっと~~ Docker Volumes をサポートしました。

https://aws.amazon.com/jp/about-aws/whats-new/2018/08/amazon-ecs-now-supports-docker-volume-and-volume-plugins/

これまでも使用できていた Bind Mounts と Docker Volumes の違いについては
Docker のドキュメントを参照いただくのがよいかと思います。

**Use volumes**
https://docs.docker.com/storage/volumes/

また Docker Volumes は Fargate ではサポートされてません。
Fargate の場合はこれまでどおり Bind Mounts を使用します。

**Docker Volumes**
https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-volumes.html

**Bind Mounts**
https://docs.aws.amazon.com/AmazonECS/latest/developerguide/bind-mounts.html

## 環境情報
以下で検証しています。

* リージョン : 東京
* AMI: amzn-ami-2018.03.d-amazon-ecs-optimized [ami-256c15c8]
* Dockerバージョン: 18.03.1-ce
* ECS Agentバージョン: 1.20.0

## タスク定義の作成
既存のタスク定義から新しいリビジョンを作成するか、タスク定義自体を新たに作成します。
ここでは既存のタスク定義を使用するため割愛しますが、検証用の Docker イメージがない場合は
以下の公式 Hello Wolrd や サンプルアプリケーションを活用するのが良いかと思います。

* Dockerイメージの作成
    * https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/docker-basics.html#docker-basics-create-image
* Amazon ECS PHP Simple Demo App
    * https://github.com/aws-samples/ecs-demo-php-simple-app

タスク定義の最下部からボリュームの追加を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/ba259beb-cfb6-b5c8-8915-0424782f9f0d.png)

ボリュームドライバーを選択してください にチェックを入れます。
ライフサイクルの違いで、2種類のスコープが利用できます。

* task : タスクの開始時に自動的にプロビジョニングされ、タスクの終了とともに削除される
* shared : タスクが停止した後も削除されない

ここでは検証のため両方のタイプのボリュームを追加します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/986c9401-d727-956f-5b97-882cc0adcac8.png)

shared の場合は事前に作成済みのボリュームを指定することも可能ですが、存在しない場合は
自動プロビジョニングを有効にする にチェックすることで、自動で作成できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/8f226c1a-5b82-a623-7c54-251ba35aad9d.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/7000eac7-a042-1385-d797-fd29aa55d8db.png)

追加したボリュームをコンテナから参照するには、コンテナ定義の ストレージとログ を設定します。
ソースボリュームで作成したボリュームを、コンテナパスでコンテナ上のマウント先を指定します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/c92ac75c-23c1-5a11-7dc3-bda38e9527c8.png)

ここでは ecs-test-volume-task を /tmp/ecs-test-volume-task に、
ecs-test-volume-shared を /tmp/ecs-test-volume-shared にマウントするよう設定します。

## サービスの作成
クラスターに新規サービスを作成するか、既存のサービスを更新して先ほど作成した
最新のタスク定義をデプロイします。
ここでは ecs-test-volume-cluster というクラスターに ecs-test-volume-service
というサービスを作成しています。
動作確認用なのでタスクの数は1です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/759c1f17-70d9-9ffb-030e-97eddefff492.png)

ネットワーク構成では、今回はネットワークモードを awsvpc に設定しているので、
VPCやセキュリティグループの情報を設定します。ELBは設定せず進みます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/d3c80aed-cd03-04d7-b1e9-0b0854ef9c80.png)

ネットワークモードの awsvpc については以前投稿した記事も参照いただければと思います。

**Amazon ECSの ネットワークモードに追加された awsvpcを試す**
https://qiita.com/hayao_k/items/ca5d326482278e325bfc

Service Auto Scaling の設定も今回は行いません。
サービスの作成が完了したら、
Service : ecs-test-volume-service で作成したタスク定義が RUNNING になっていることを確認します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/a26e803b-f72a-f029-a5a2-68991b25cdeb.png)

## 動作確認(ボリュームの確認)
ECSインスタンスにログインして、ボリュームが作成されていることを確認します。

```bash
$ docker volume ls
DRIVER              VOLUME NAME
local               ecs-console-sample-app-static-6-ecs-test-volume-task-86e4a5c4adddc180db01
local               ecs-test-volume-shared
```
スコープが task の場合は VOLUME NAME は自動的に設定されるようです。
inspect で確認すると、ボリュームが /var/lib/docker/volumes 配下に作成されているのがわかります。

```bash
$ docker volume inspect ecs-console-sample-app-static-6-ecs-test-volume-task-86e4a5c4adddc180db01
[
    {
        "CreatedAt": "2018-08-13T09:37:54Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/ecs-console-sample-app-static-6-ecs-test-volume-task-86e4a5c4adddc180db01/_data",
        "Name": "ecs-console-sample-app-static-6-ecs-test-volume-task-86e4a5c4adddc180db01",
        "Options": null,
        "Scope": "local"
    }
]

$ docker volume inspect ecs-test-volume-shared
[
    {
        "CreatedAt": "2018-08-13T09:37:54Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/ecs-test-volume-shared/_data",
        "Name": "ecs-test-volume-shared",
        "Options": null,
        "Scope": "local"
    }
]
```

次にコンテナに接続して確認します。
設定したパスにボリュームがマウントされていることが確認できます。

```bash
$ docker exec -it <CONTAINER ID> /bin/bash
root@ip-10-0-1-238:/# df -h
Filesystem                         Size  Used Avail Use% Mounted on
/dev/mapper/docker-202:～          9.8G  250M  9.0G   3% /
tmpfs                               64M     0   64M   0% /dev
tmpfs                              493M     0  493M   0% /sys/fs/cgroup
/dev/xvda1                         7.8G  781M  6.9G  10% /tmp/ecs-test-volume-task
/dev/xvda1                         7.8G  781M  6.9G  10% /tmp/ecs-test-volume-shared
/dev/xvda1                         7.8G  781M  6.9G  10% /etc/resolv.conf
/dev/xvda1                         7.8G  781M  6.9G  10% /etc/hostname
/dev/xvda1                         7.8G  781M  6.9G  10% /etc/hosts
shm                                 64M     0   64M   0% /dev/shm
tmpfs                               64M     0   64M   0% /proc/kcore
tmpfs                               64M     0   64M   0% /proc/keys
tmpfs                               64M     0   64M   0% /proc/latency_stats
tmpfs                               64M     0   64M   0% /proc/timer_list
tmpfs                               64M     0   64M   0% /proc/sched_debug
tmpfs                              493M     0  493M   0% /proc/scsi
tmpfs                              493M     0  493M   0% /sys/firmware
```

最後にタスクを終了させて task と shared のスコープによる動作の違いを確認します。
しかし直接サービスを削除したところ、スコープが task のボリュームが残った状態になってしまいました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/f90e16ba-3445-3b66-5f0a-9fd7aab31dfb.png)

```bash
$ docker volume ls
DRIVER              VOLUME NAME
local               ecs-console-sample-app-static-6-ecs-test-volume-task-86e4a5c4adddc180db01
local               ecs-test-volume-shared
```

もう一度サービスを作成し、サービスの更新でタスクの数を1→0に設定しても同様の挙動で
task の ボリュームが残ったままになってします。。。

```bash
$ docker volume ls
DRIVER              VOLUME NAME
local               ecs-console-sample-app-static-6-ecs-test-volume-task-86e4a5c4adddc180db01
local               ecs-console-sample-app-static-6-ecs-test-volume-task-e4dcf8d8b9ffaced2000
local               ecs-test-volume-shared
```

サービスからタスクを起動するのではなく、タスクから 新しいタスクの実行 で試してみます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/ad34d217-62ff-aa4f-23ba-92aa1c9afda6.png)

タスクから 起動したタスクを停止します。
やはりボリュームが残ったままになってしまいました。

```bash
$ docker volume ls
DRIVER              VOLUME NAME
local               ecs-console-sample-app-static-6-ecs-test-volume-task-86e4a5c4adddc180db01
local               ecs-console-sample-app-static-6-ecs-test-volume-task-8ccc95efa8cdccc24200
local               ecs-console-sample-app-static-6-ecs-test-volume-task-e4dcf8d8b9ffaced2000
local               ecs-test-volume-shared
```

~~そもそもタスクの停止時に task のボリュームが消えるという認識自体が違うのかもしれません。~~
~~このあたりの挙動については引き続き調査したいと思います。~~
以下追記を参照

## 2018/8/15 追記
scope を task に設定したボリュームは、ECS Agentの設定により、デフォルトで3時間後に削除されます。

**Amazon ECS コンテナエージェントの設定**
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs-agent-config.html

> ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION
> > 値の例: 1h (有効な時間単位は「ns」、「us」 (または「µs」)、「ms」、「s」、「m」、および「h」です。)
> > Linux のデフォルト値: 3h
> > Windows のデフォルト値: 3h
> > タスクが停止してから Docker コンテナが削除されるまでの待機時間。これは Docker コンテナのデータを削除するため、この値の設定が小さすぎると、削除される前に停止したコンテナを調べたりログを確認したりできない場合があることに注意してください。最小の期間は 1m です。1 分より短い値は無視されます。

ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION に設定した値が経過後にコンテナが削除されますが、
その際に一緒に scope が task であるボリュームも削除されるようです。

デフォルト値を変更したい場合は設定ファイルに以下の行を追記し、変更を反映させます。
ただしドキュメントに記載にある通り、この間隔で停止したコンテナの削除も行われますのでご注意ください。

```/etc/ecs/ecs.config
ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION=1m ★1分で削除に変更
```

この設定で改めて確認したところ、タスク停止の1分後にコンテナおよび scope をタスクに設定した
ボリュームが削除され、sharedのボリュームは残ったままであることを確認できました。
もちろんデフォルトの設定であれば3時間後に削除されます。

```bash
$ docker volume ls
DRIVER              VOLUME NAME
local               ecs-console-sample-app-static-6-ecs-test-volume-task-8cdcfbddf8839bfe4e00
local               ecs-test-volume-shared

# タスク停止1分後、コンテナが削除されAgentのみが起動されている状態
$ docker ps -a
CONTAINER ID        IMAGE                            COMMAND             CREATED             STATUS              PORTS               NAMES
412d92017deb        amazon/amazon-ecs-agent:latest   "/agent"            7 minutes ago       Up 7 minutes                            ecs-agent

# scope:task のボリュームも削除されている
$ docker volume ls 
DRIVER              VOLUME NAME
local               ecs-test-volume-shared
```

以上です。
参考になれば幸いです。