AWS ECS コンテナ毎のメトリクスを取得する

AWS ECS でコンテナ毎のメトリクス（CPU使用率やメモリ使用率など）を取得する方法です。
ECSの起動タイプはEC2、Fargateにて確認しています。

取得できるメトリクスは以下サイトの「Type: Container」に記載のある項目です。
[Amazon ECS の Container Insights パフォーマンスログイベント](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-reference-performance-logs-ECS.html)

# 概要
CloudWatch Container Insightsを有効にしたECSクラスターは、コンテナのメトリクス情報
（パフォーマンスログ）がCloudWatch Logsに出力されます。
そのログに対してCloudWatch Logs Insightsでクエリを実行することでメトリクスを取得できます。
本記事ではCPU使用率とメモリ使用率を取得します。

## CloudWatch Logs Insightsを使う理由
ECSのメトリクスを取得する方法は他にもあると思いますが、以下に挙げる方法は使いづらい点があります。

- CloudWatch Container Insightsのダッシュボード  
  - コンテナ毎の詳細なメトリクスがない。Container Insightsはクラスター毎、サービス毎、タスク毎のメトリクスをグラフ表示しますが、コンテナ毎のメトリクスは以下のように平均値しかありません。タスク内にコンテナを1つしか定義していない場合はタスク毎のメトリクスで十分な場合もありますが、複数定義している場合に困ることがあります。
  ![Container Insights コンテナのパフォーマンス](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572307/831e4e80-22d5-e3e1-c6c5-ec31980581c3.png)
  - Container Insightsのタスク毎のグラフは複数のタスクが同時に起動している場合、合算集計されたグラフになります。特定のタスクのみの結果が欲しい場合、CloudWatch Logs InsightsでタスクIDを絞る必要があります。
  
- コンテナのホストであるEC2上でdocker stats等のコマンドを実行
  - FargateではホストのEC2が不可視のためこの方法は実行不可。
  - EC2にSSH接続やRDP接続で乗り込まないといけないので手間。

# 事前準備
## ECSクラスターのContainer Insightsを有効にしておく
ECSクラスターのContainer Insightsを有効にしておくことで、CloudWatch Logsにパフォーマンスログが出力されます。
Container Insightsを有効にする方法はこちらをご確認ください。
[クラスターおよびサービスレベルの Amazon ECS でメトリクスの Container Insights の設定](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/deploy-container-insights-ECS-cluster.html)

# 集計実施
## CloudWatch Logs Insightsでクエリを実行する
以下項目を入力し、クエリの実行をします。
　① ロググループ
　　　ECSコンテナのパフォーマンスログは以下名称で作成されています。
　　　`/aws/ecs/containerinsights/{クラスター名}/performance`
　②集計対象の期間
　③クエリ文
　　　[クエリ文](#クエリ文) 参照
![Logs Insights クエリ実行](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572307/f5cb8bc4-58c3-e922-cd21-817b802e0da1.png)


## クエリ文
```
fields @timestamp, CpuUtilized, CpuReserved, CpuUtilized * 100 / CpuReserved as CpuUtilization,
        MemoryUtilized, MemoryReserved, MemoryUtilized * 100 / MemoryReserved as MemoryUtilization
| filter ContainerName = "XXXXXXXXXXXXXXXXXX" and Type = "Container" and TaskId = "XXXXXXXXXXXXXXXXXX"
| sort @timestamp asc
| limit 10000
```
- fields : 取得するメトリクス。上記クエリの内容は下表参照。
- filter : コンテナ名、パフォーマンスログの種類、タスクIDで集計対象のログをフィルタ。   
           ※コンテナ名、タスクIDは環境に合わせて設定。
- sort : タイムスタンプの昇順に表示。（デフォルトは降順）
- limit : 取得するログ件数。最大10,000。（デフォルトは1,000）

|fields|内容|
|:--|:--|
|@&#xFFF0;timestamp|パフォーマンスログのタイムスタンプ|
|CpuUtilized|CPUユニット数の使用量|
|CpuReserved|コンテナに対するCPUユニット数の割り当て|
|CpuUtilization|CPU使用率（CpuUtilized * 100 / CpuReserved で計算[^1]）|
|MemoryUtilized|メモリ使用量（MiB）|
|MemoryReserved|コンテナに対するメモリの割り当て（MiB）|
|MemoryUtilization|メモリ使用率（MemoryUtilized* 100 / MemoryReservedで計算[^1]）|

CloudWatch Logs Insightsのクエリ文の書き方詳細は以下参照。
[CloudWatch Logs Insights のクエリ構文](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html)

[^1]: 分母はコンテナに割り当てられたリソースであることに注意。EC2のリソースやタスクに割り当てたリソースではない。

## 実行結果
![Logs Insights 実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572307/85319b98-e6cd-f32a-3d84-374c4c25281a.png)
「結果をエクスポート」からCSV形式およびMarkdown形式で上記を出力できます。
CSVから簡単にグラフにできますね。

なお、ECSコンテナのパフォーマンスログは1分おきに出力されるため、それ以上細かい時間でのメトリクスは取得できません。