ECS で Container Insights を使ってみた

# はじめに

Amazon ECS に、Container Insights というコンテナワークロードに特化したモニタリング機能があります。ECS クラスターで稼働するサービスやタスクを一目で把握する可視化機能や、サービス単位のパフォーマンスメトリクスを確認する機能があります。また、サービス配下のタスク単位では、最新時刻のパフォーマンスを確認する機能があり、タスクに対する負荷の集中が確認しやすくなります。

Container Insights は、簡単に始められるので有効化の方法を確認してみましょう。



# Container Insights の有効化

Amazon ECS クラスターの詳細画面を引きます。CloudWatch monitoring に Default と表示されている場合は、Container Insights は無効化となっています。

![image-20221113152834254.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/6296897c-283c-8453-6764-fb0ec24bb112.png)



既存の ECS クラスターの有効化は、マネージメントコンソールでは出来ません。AWS CLI から有効化が可能です。次のコマンドを実行します。

```
aws ecs update-cluster-settings --cluster test-cluster01 --settings name=containerInsights,value=enabled
```



Container Insights が有効になりました。有効にしてから、約 5分ほど待機すると、CloudWatch の画面に反映されました。すぐ確認しても表示されないので、多少待ちましょう。

![image-20221113153419000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3bad2375-d847-fc5a-42a8-973cef9c725e.png)



# Container Insights を確認

いくつかのシナリオを基に、Container Insights の使い方を見ていきましょう。



## クラスターの全体像を確認

CloudWatch のメニューから、Container Insights を選択します。画面内のプルダウンで、Container map を選択します。

![image-20221113173230391.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/80c7f9e6-154a-4459-5be1-1c0eadc9fddb.png)



Container Insights が有効になっている全クラスタの状態が見えます。特定のクラスタだけ見たい場合は、Filter からクラスタ名を選択します。

![image-20221113173444164.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/01720093-3067-06cc-1030-3aca8184a5ad.png)



ECS の Service と Task が並べて表示されております。より直感的に確認するために、Refresh を押します。

![image-20221113173624013.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/0715a654-1aeb-1216-85c7-5a9e1c113d75.png)



Service に紐づく形で、Task が表示されました。これで、クラスタ内に稼働するサービスと、それに紐づく Task の概要がわかります。また、アイコンの色が緑色ではない場合は、CPU などのリソースの状況が良くない可能性を示しています。黄色の段階では、まだ大丈夫かもしれませんが、確認してみると良いでしょう。

![image-20221113173726047.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/ff4003dc-e4ea-5fd6-096c-74a6f2c229c5.png)



## サービス単位のパフォーマンスを確認

Performance monitoring を確認

![image-20221113220758172.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/cc293d05-110f-e09e-a9a1-4ed0fe443aeb.png)



調査したいサービスを選択

![image-20221113220854631.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/6bc7a9df-7376-0295-2d79-e90fb4d0ed6b.png)



サービス配下で稼働するタスクを全てまとめた形で、CPU やメモリや、稼働すべきタスクの数、現在稼働しているタスクの数が見えます。

![image-20221113221003190.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/2d710e30-cae0-2210-73b7-ac69b8bf99d9.png)



## Task 単位のパフォーマンスを確認

Performance monitoring の画面には、Task 単位での CPU やメモリの使用率がわかります。現時点での最新の状況しかわらかないため、過去の履歴は見えない点は留意しておきましょう。

![image-20221113221145800.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/19f179f2-a8e0-1d09-3492-34ab4c0078db.png)



## Task のログを検索

該当の Task を選択して、アプリケーションのログを検索することが出来ます。選択して、View application logs を押します。

![image-20221113221223390.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/7f97ffe7-0198-d827-fa4a-231a73794cb5.png)



Run query を押す

![image-20221113221300290.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/4015680c-ba6d-2a8b-af93-6837f96db1c1.png)



ログを検索が出来ます。

![image-20221113221417467.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/7f2fb37a-5d73-65bd-a6db-f392d6641838.png)



# 余談 : Task 単位の過去メトリクス確認

あまり実用的ではないかもしれないですが、Task 単位の過去のメトリクスを確認するための Dashboard が公開されています。これを import することで、Task 単位の CPU や Memory の使用率を確認できます。ただ、表示する Task は動的に更新されるわけではなく、import の時に task id を指定する形になるため、Task の再作成に自動追従することが出来ません。

GitHub : https://github.com/mreferre/container-insights-custom-dashboards



作業用ディレクトリを適当に作成して、GitHub から clone します。

```
mkdir ~/temp/container-insights-custom-dashboards
cd ~/temp/container-insights-custom-dashboards
git clone https://github.com/mreferre/container-insights-custom-dashboards.git
```



ディレクトリを移動します。

```
cd container-insights-custom-dashboards/container-level-metrics
```



`container-level-metrics.json` に手を加えていきます。クラスタ名を指定します。

```
sed -i 's/CLUSTERNAME/test-cluster01/g' container-level-metrics.json
```



タスクid、コンテナid を指定します。

```
sed -i 's/CONTAINERNAMEREPLACEME/hello-ber/g' container-level-metrics.json
sed -i 's/TASKIDREPLACEME/2a0e0d90e4634989ab76ac313b7e9452/g' container-level-metrics.json
```



region を東京に指定します。

```
sed -i 's/us-west-2/ap-northeast-1/g' container-level-metrics.json
```





変更後の json ファイルです。

```
{
    "start": "-PT168H",
    "widgets": [
        {
            "height": 6,
            "width": 15,
            "y": 0,
            "x": 0,
            "type": "log",
            "properties": {
                "query": "SOURCE '/aws/ecs/containerinsights/test-cluster01/performance' | fields @message\n| filter Type=\"Container\" and TaskId=\"2a0e0d90e4634989ab76ac313b7e9452\"\n| filter @logStream like \"FargateTelemetry\"\n| stats  max(CpuReserved) as ContainerCpuReserved, max(CpuUtilized) as PeakCpuUtilized, avg(CpuUtilized) as AvgCpuUtilized by ContainerName | sort ContainerName asc",
                "region": "ap-northeast-1",
                "stacked": false,
                "title": "CPU usage by Container",
                "view": "table"
            }
        },
        {
            "height": 6,
            "width": 15,
            "y": 6,
            "x": 0,
            "type": "log",
            "properties": {
                "query": "SOURCE '/aws/ecs/containerinsights/test-cluster01/performance' | fields @message\n| filter Type=\"Container\" and TaskId=\"2a0e0d90e4634989ab76ac313b7e9452\"\n| filter @logStream like \"FargateTelemetry\"\n| stats  max(MemoryReserved) as ContainerMemoryReserved, max(MemoryUtilized) as PeakMemoryUtilized, avg(MemoryUtilized) as AvgMemoryUtilized by ContainerName | sort ContainerName asc",
                "region": "ap-northeast-1",
                "stacked": false,
                "title": "Memory usage by container",
                "view": "table"
            }
        },
        {
            "height": 6,
            "width": 9,
            "y": 0,
            "x": 15,
            "type": "log",
            "properties": {
                "query": "SOURCE '/aws/ecs/containerinsights/test-cluster01/performance' | fields @message\n| filter Type=\"Container\" and ContainerName=\"hello-ber\" and TaskId=\"2a0e0d90e4634989ab76ac313b7e9452\"\n| filter @logStream like /FargateTelemetry/\n| stats  avg(CpuUtilized) as AvgCpuUtilized, max(CpuReserved) as ContainerCpuReserved by bin(30m)\n",
                "region": "ap-northeast-1",
                "stacked": false,
                "title": "CPU usage for selected container",
                "view": "timeSeries"
            }
        },
        {
            "height": 6,
            "width": 9,
            "y": 6,
            "x": 15,
            "type": "log",
            "properties": {
                "query": "SOURCE '/aws/ecs/containerinsights/test-cluster01/performance' | fields @message\n| filter Type=\"Container\" and ContainerName=\"hello-ber\" and TaskId=\"2a0e0d90e4634989ab76ac313b7e9452\"\n| filter @logStream like /FargateTelemetry/\n| stats ceil(avg(MemoryUtilized)) as AvgMemUtilized, max(MemoryReserved) as ContainerMemoryReserved by bin(30m)\n",
                "region": "ap-northeast-1",
                "stacked": false,
                "title": "Memory usage for selected container",
                "view": "timeSeries"
            }
        },
        {
            "height": 9,
            "width": 24,
            "y": 12,
            "x": 0,
            "type": "log",
            "properties": {
                "query": "SOURCE '/aws/ecs/containerinsights/test-cluster01/performance' | fields @message\n| filter Type=\"Task\" and TaskId=\"2a0e0d90e4634989ab76ac313b7e9452\"\n| filter @logStream like \"FargateTelemetry\"\n| stats latest(TaskDefinitionFamily) as TaskDefFamily, latest(TaskDefinitionRevision) as Rev, latest(ServiceName) as Service, latest(ClusterName) as Cluster, max(CpuReserved) as TaskCpuReserved, avg(CpuUtilized) as AvgCpuUtilized, concat(ceil(avg(CpuUtilized) * 100 / TaskCpuReserved),\" %\") as AvgCpuUtilizedPerc, max(CpuUtilized) as PeakCpuUtilized, concat(ceil(max(CpuUtilized) * 100 / TaskCpuReserved),\" %\") as PeakCpuUtilizedPerc, max(MemoryReserved) as TaskMemReserved, ceil(avg(MemoryUtilized)) as AvgMemUtilized, concat(ceil(avg(MemoryUtilized) * 100 / TaskMemReserved),\" %\") as AvgMemUtilizedPerc, max(MemoryUtilized) as PeakMemUtilized, concat(ceil(max(MemoryUtilized) * 100 / TaskMemReserved),\" %\") as PeakMemUtilizedPerc",
                "region": "ap-northeast-1",
                "stacked": false,
                "title": "Fargate task details",
                "view": "table"
            }
        }
    ]
}
```



AWS CLI でダッシュボードを import します。

```
aws cloudwatch put-dashboard --dashboard-name container-level-metrics --dashboard-body file://./container-level-metrics.json
```





決め打ちで 1 つの Task に関する過去の状況が見えます。ただ、Task の再作成などのタイミングで、Task id が変わるので、使いにくいかもしれません

![image-20221113224209610.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/a32d388e-8dd5-baf5-f46c-1e30f9b73c58.png)



# わかったこと

- Container Insights
  - Task レベルのパフォーマンスは、現在のメトリクスしか見えない (過去のメトリクスを使った可視化などは難しい)
  - Service の単位では、過去のメトリクスを使って可視化が可能
- GitHub に公開されている Dashboard を import することで、Task ID を決め打ちで指定した可視化は可能
  - ただ、Task の再作成で Task ID が変わるため、この自動化は難しい
  - Lambda などによる自動化を作り込めばいけるかもしれない
  - CloudWatch Logs Insights のクエリーの書き方を工夫すれば、もしかしたら余地はあるかもしれない。



# 参考 URL

https://dev.classmethod.jp/articles/container-insights-ga/#toc-1