ecs-agentの設定を見直して、ECS on EC2のディスクフル対策をする

この記事は[リンクアンドモチベーション Advent Calendar 2023](https://qiita.com/advent-calendar/2023/lmi)の9日目の記事です。

# はじめに

弊社ではAmazon ECS (以下ECS) を各プロダクトのインフラ基盤として採用しています。

https://speakerdeck.com/lmi/introduction-to-link-and-motivation-for-software-engineers?slide=29

一部のプロダクトでECS on EC2を利用しているのですが、たまにEC2側のディスクフルが発生しECSのデプロイに失敗するケースがあったため、調査の内容と対応について紹介します。

# 発生起因

毎回発生するわけではないのですが、主な発生起因としては以下のようなケースでした。

 - 同じクラスター(EC2)に短期間に何度もデプロイした際
 - ECSの起動に失敗し、停止 -> 起動を繰り返した際

その結果として停止済みのコンテナが大量に残存し、EC2側のディスクを食い潰していました。

```bash
[ec2-user@ip-172-30-33-173 ~]$ docker container ls -a | grep Exited | wc -l
99
[ec2-user@ip-172-30-33-173 ~]$

[ec2-user@ip-172-30-33-173 ~]$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme0n1p1   30G   29G  1.4G  96% /
[ec2-user@ip-172-30-33-173 ~]$
```

# 解決方法

ECS on EC2の場合、task定義で指定されているコンテナ以外にecs-agentというコンテナが起動していると思います。
AMIによって元々インストールされていたり、自身でインストールする必要があります。

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs-agent-install.html

```bash
[ec2-user@ip-172-30-33-173 ~]$ docker container ls | grep ecs-agent
5a015f17f960   amazon/amazon-ecs-agent:latest   "/agent"   35 minutes ago   Up 35 minutes (healthy)             ecs-agent
[ec2-user@ip-172-30-33-173 ~]$
```

ecs-agentはECSの設定や操作に応じて、EC2上のコンテナの管理をしてくれます。
その中で停止しているコンテナのクリーンアップもしてくれるのですが、その処理に関するパラメータを調整することで解決しました。

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/automated_image_cleanup.html

今回は `ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION` の値を調整しました。
こちらは停止しているコンテナの削除周期ですが、デフォルトだと3時間になっています。
この場合EC2のボリュームサイズやコンテナイメージのサイズによっては、削除が間に合わなくなるためデフォルトの3hから30mに変更しました。

変更する際は `/etc/ecs/ecs.config`に記載してあげると反映されます。

```bash
[ec2-user@ip-172-30-40-245 ~]$ grep ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION /etc/ecs/ecs.config
ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION=30m
[ec2-user@ip-172-30-40-245 ~]$
```

その他のパラメータについては下記から確認できます。

https://github.com/aws/amazon-ecs-agent/blob/master/README.md#environment-variables

上記の設定を反映させた結果停止後30分経過したコンテナは削除されるようになり、ディスクフルが発生しなくなりました。

```bash
[ec2-user@ip-172-30-40-245 ecs]$ docker container ls -a | grep Exited | tail -n 1
b3974cd9e1f3   {image名}   "/bin/sh -c /entrypo…"   27 minutes ago      Exited (0) 26 minutes ago              {task名}
[ec2-user@ip-172-30-40-245 ecs]$
```

ecs-agentのログは以下から確認できます。
以下のようなログの発生頻度から設定が反映されていること、古いコンテナの削除がされていることを確認できます。

```bash
[ec2-user@ip-172-30-40-245 ~]$ grep "Removing container" /var/log/ecs/ecs-agent.log | tail -n 5
level=info time=2023-12-06T05:44:15Z msg="Removing container" containerName="aaa" containerImage="{イメージリポジトリ}:latest" containerKnownStatus="STOPPED" containerDesiredStatus="STOPPED" containerExitCode="0" task="{タスク}"
level=info time=2023-12-06T05:44:15Z msg="Removing container reference from image state" container="aaa" image="{イメージリポジトリ}:latest" state="sha256:hoge"
level=info time=2023-12-06T05:44:15Z msg="Removing container" containerName="bbb" containerImage="{イメージリポジトリ}:202310161508" containerKnownStatus="STOPPED" containerDesiredStatus="STOPPED" containerExitCode="1" task="{タスク}"
level=info time=2023-12-06T05:44:15Z msg="Removing container reference from image state" container="bbb" image="{イメージリポジトリ}:202310161508" state="sha256:fuga"
level=info time=2023-12-06T05:44:15Z msg="Removing container" containerDesiredStatus="STOPPED" containerExitCode="nil" containerName="nginx" containerImage="public.ecr.aws/nginx/nginx:1.25.1" containerKnownStatus="STOPPED" task="{タスク}"
[ec2-user@ip-172-30-40-245 ~]$
```

# まとめ

今回こちらの対応をするまでは恥ずかしながら、発生するたびに都度EC2にログインして `docker system prune -a` 実行していて完全なトイルになっていました。
AWSのSAさんに相談したところサクッとこちらの設定について教えていただき助かりました。