EC2 Amazon Linuxでカスタムメトリクスを取得する方法（なるべくコマンド叩かない方法）

# なぜカスタムメトリクスを取得するか

EC2のCPUやネットワークIOはCloudWatchで簡単に確認できますが、メモリやDISKの利用状況はCloudWatch Agentを使ってカスタムメトリクスを取得しないとCloudWatch上で確認することができません。
カスタムメトリクスさえ取れれば、CloudWatch AlarmやCloudWatchを読み込める監視ツール(Zabbixなど)で通知もできるようになるので、サービスを稼働させているEC2インスタンスでは取得しておくと良いと思います。

# カスタムメトリクスの取得方法の概要

### 今までの取得方法

カスタムメトリクスを取得するには、以下の方法がありました。

- 公式から配布されているperlのスクリプトを使う [参考記事](https://qiita.com/masarufuruya/items/212adbfb285476683c47)
- AWS SDKを使ったスクリプトを自作 [参考記事](https://dev.classmethod.jp/cloud/aws/put-diskusage-to-cloudwatch-using-go/)
- AWS CLIを使ったスクリプトを自作 [参考記事](https://dev.classmethod.jp/cloud/aws/custommetrics-bashtemplate/)

### CloudWatchエージェント

2017年12月以降、[AWS公式ガイド](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html)によると、RPMでCloudWatchエージェントを導入する方法が掲載されています。

新しいCloudWatchエージェントの特徴は、取得するメトリクスの種類やスパンを、AWS Systems Managerパラメータストアに定義できるというところだと思います。
今までの方法ですと、取得するメトリクスを増やしたい場合はスクリプトを書き換える必要があったり、取得スパンを変更したい場合はcrontabを変更する必要があったりと、EC2にログインして作業する必要がありました。
新しいCloudWatchエージェントの場合は、AWSマネジメントコンソール上でJSON形式の定義ファイルを書き換えるだけで、取得するメトリクスの種類やスパンを変更することができるというメリットがあります。

これだけではなく、導入がRPM一発と非常に簡単ですし、crontabの必要もなく、初期設定はダイアログ形式でよいなど、今までの方法に比べてカスタムメトリクスを取得する敷居がぐんと下がったと思います。

# CloudWatchエージェントを動かすために必要なAWSサービス

パラメータストアという概念に触れたことが無い方もいらっしゃると思います。
私は新しいCloudWatchエージェントを動かすにあたって初めて触りました・・・

関連するサービスを一旦ここで説明します。

### IAM
AWS Identity and Access Managementの略称です。
所謂「ユーザー」のようなものだと思っていただければ大体あっていると思います。
AWSの「どのサービスのどのインスタンスにどの操作ができるか」といったアクセス権限を事細かに設定することができます。

以下のようなことをしたい時にIAMの設定が必要になります。

- AWSコンソールへのログインと操作（ブラウザから）
- AWS CLI（コマンドラインツール）を使った操作
- AWS SDKを使った操作
- AWS APIを使った操作

ブラウザログインの際はパスワードを使うことになります。
CLI・SDK・APIを使う時はアクセスキーIDとシークレットアクセスキーを使うことになります。

ただし、EC2のインスタンスに対してIAMロール（権限の集合体）を直接指定することができます。
そうすると、アクセスキーIDとシークレットアクセスキーを発行せずともEC2のインスタンスからAWS CLIを使えるようになります。

### System Manager

詳しくはよくわかっておりませんが・・・

AWSのサービスを横串で管理するインターフェースのようです。
EC2インスタンスの停止・起動や、AMIの更新の自動化など、様々なオートメーション化も出来るようです。

パラメータストアはSystem Managerの一機能です。
EC2などで利用する環境変数を、AWS上に保存することができます。

パラメータストア上の値を変更すると、EC2でパラメータストアを参照するように設定していればにEC2にログインせずに環境変数を変更することが出来るというものです。
※パラメータストアと常時同期しているわけではないと思うので、パラメータストアの参照タイミングは気にしておいた方がよさそうです。

あまりよく理解してはいないのですが、今回はどのカスタムメトリクスをどのタイミングで取得するのか、という設定ファイルをパラメータストアに保存しておくことになります。

### CloudWatch

利用しているAWSサービスの各種メトリクスを確認することができます。
CLIやSDKを通じてメトリクスを取得し、ZabbixやNew Relicなどの監視ツールで確認することも可能です。

# CloudWatchエージェントを使ったカスタムメトリクスの取得方法

ここからが具体的な取得手順です。
CloudWatchエージェントでの確認取得方法の記事は沢山あると思いますが、基本的には以下の違いになるかと思います。

- IAMの権限をどう指定するか
    - パラメータストアへの書き込み権限を付けるかどうか
    - EC2にロールをアタッチするかIAMユーザーを作るか（アクセスキーを発行するかしないか）
- CloudWatchエージェントのダイアログ形式の設定スクリプトを使うかどうか
    - 「どのタイミングでどのカスタムメトリクスの習得するのか」という設定値をどのように定義するか
- CloudWatchエージェント起動時にどの設定を読み込むか
    - パラメータストアから読み込むかEC2ローカルの設定ファイルを読み込むか

今回は、以下の組み合わせで設定を行います。

- IAMにパラメータストアへの書き込み権限を付けない
    - パラメータストアへはAWSコンソール（ブラウザ）から設定を書き込む
- EC2にロールをアタッチする
    - IAMユーザーは作らない
- CloudWatchエージェントのダイアログ形式の設定スクリプトは使わない
- CloudWatchエージェント起動時にパラメータストアから設定を読み込む

## パラメータストアに取得内容を定義

「どのタイミングでどのカスタムメトリクスを取得するか」という設定を、JSON形式でパラメータストアに定義します。

この設定のJSONはCloudWatchエージェントのダイアログ形式の設定スクリプトから生成できますので、細かく調整したい方はそちらを使って生成してみてください。
今回は、以下の3パターンを提示します。

- 今回カスタマイズした最小のメトリクス
    - DISKの使用率とメモリの使用率のみ
- Basicなメトリクス
    - メモリとSwapの使用率
    - ダイアログ形式の設定スクリプトでBasicを指定した場合に生成されるもの
- Standardなメトリクス
    - CPUとDISKとメモリとSwapの使用状況
    - ダイアログ形式の設定スクリプトでStandardを指定した場合に生成されるもの

取得タイミングは60秒間隔、ログファイルは含めないとしています。
とりあえず動かしたい方は、これらのJSONから好きなのを選んでパラメータストアに保存してください。

```json:超最小のメトリクス
{ "metrics": { "append_dimensions": { "AutoScalingGroupName": "${aws:AutoScalingGroupName}", "ImageId": "${aws:ImageId}", "InstanceId": "${aws:InstanceId}", "InstanceType": "${aws:InstanceType}" }, "metrics_collected": {"disk": { "measurement": [ "used_percent" ], "metrics_collection_interval": 60, "resources": [ "*" ] }, "mem": { "measurement": [ "mem_used_percent" ], "metrics_collection_interval": 60 } } } }
```

```json:Basicなメトリクス
{ "metrics": { "append_dimensions": { "AutoScalingGroupName": "${aws:AutoScalingGroupName}", "ImageId": "${aws:ImageId}", "InstanceId": "${aws:InstanceId}", "InstanceType": "${aws:InstanceType}" }, "metrics_collected": { "mem": { "measurement": [ "mem_used_percent" ], "metrics_collection_interval": 60 }, "swap": { "measurement": [ "swap_used_percent" ], "metrics_collection_interval": 60 } } } }
```

```json:Standardなメトリクス
{ "metrics": { "append_dimensions": { "AutoScalingGroupName": "${aws:AutoScalingGroupName}", "ImageId": "${aws:ImageId}", "InstanceId": "${aws:InstanceId}", "InstanceType": "${aws:InstanceType}" }, "metrics_collected": { "cpu": { "measurement": [ "cpu_usage_idle", "cpu_usage_iowait", "cpu_usage_user", "cpu_usage_system" ], "metrics_collection_interval": 60, "resources": [ "*" ], "totalcpu": false }, "disk": { "measurement": [ "used_percent", "inodes_free" ], "metrics_collection_interval": 60, "resources": [ "*" ] }, "diskio": { "measurement": [ "io_time" ], "metrics_collection_interval": 60, "resources": [ "*" ] }, "mem": { "measurement": [ "mem_used_percent" ], "metrics_collection_interval": 60 }, "swap": { "measurement": [ "swap_used_percent" ], "metrics_collection_interval": 60 } } } }
```

例として、「超最小のメトリクス」のJSONに AmazonCloudWatch-linux-minimum という名前を付けて、パラメータストアに設定します。

- Parameter Storeを選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106949/0724581c-c046-695b-e5e1-7b500bd4237d.png)

- パラメータを作成ボタンから進みます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106949/e717fdfa-30a3-7bf0-3294-6360f0f728b5.png)

- AmazonCloudWatch-linux-minimum という名前をつけてJSONを入力します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106949/751ea268-746c-b716-e0ff-bcb6df306c0e.png)

- 作成後はこのような画面になります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106949/6593c698-aa89-e7cd-96a8-33e1f2500e0d.png)

## IAMロールの作成

CloudWatchエージェントは、IAMを使ってカスタムメトリクスをCloudWatchに送信します。
IAMユーザーは作成せずに、IAMロールを作るところまで行います。

CloudWatchAgentServerPolicy というポリシーがデフォルトで用意されています。
CloudWatchAgentServerPolicy をアタッチした CloudWatchAgentServerRole というロールを作成してください。
※以前は自分で定義する必要がありましたが、いつからかデフォルトに追加されていました。

- EC2を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/106949/264f31ed-4278-3c03-d8fd-3babc313b463.png)

- CloudWatchAgentServerPolicy を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106949/1993fefb-e47e-ed26-b558-e3e4c036be2f.png)

- CloudWatchAgentServerRole という名前を付けます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106949/28f42545-a0fc-c5ea-0d47-0d5eee0ec06e.png)


## EC2インスタンスにIAMロールをアタッチ

EC2自体にIAMロールと同じ権限を持たせるというものです。
これによって、IAMユーザーのアクセスキーIDとシークレットアクセスキーをEC2上に配置しなくても、CLIが使えるようになります。

- インスタンスを選択して「IAMロールの割当/置換」を選択します。

![EC2 Management Console.png](https://qiita-image-store.s3.amazonaws.com/0/106949/15a866aa-36ed-c0ec-1d70-f19bac82a206.png)

- CloudWatchAgentServerRole を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106949/c311b6ef-8b20-23e7-3679-bff0126ca889.png)

## CloudWatchエージェントの導入

CloudWatchエージェントをAmazon Linuxにインストールします。

EC2インスタンスにSSHログインして、以下のコマンドを実行してください。
zipファイルをDL/unzipしてinstall.shが実行され、RPM経由でCloudWatchエージェントがインストールされます。

```bash
$ mkdir install
$ cd install
$ wget https://s3.amazonaws.com/amazoncloudwatch-agent/linux/amd64/latest/AmazonCloudWatchAgent.zip
$ unzip AmazonCloudWatchAgent.zip
$ sudo ./install.sh
```

## CloudWatchエージェント起動

以下のようにコマンドを叩くと、CloudWatchエージェントが起動します。
`amazon-cloudwatch-agent-ctl` から起動することでインスタンス再起動後も、同じ設定のまま起動するようになります。

`-c` オプションには、パラメータストアで作成したパラメータを指定します。
`-a fetch-config` は、パラメータストアから値を取得するということを意味してるようです。

```bash
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c ssm:AmazonCloudWatch-linux-minimum -s
```

以下のようにログが出力されて実行されたことが確認できます。

```bash
/opt/aws/amazon-cloudwatch-agent/bin/config-downloader --output-file /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json --download-source ssm:AmazonCloudWatch-linux-minimum --mode ec2 --config /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml
Start configuration validation...
/opt/aws/amazon-cloudwatch-agent/bin/config-translator --input /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json --output /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml --mode ec2 --config /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml
Valid Json input schema.
No log configuration found.
Configuration validation first phase succeeded
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent -schematest -config /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml
Configuration validation second phase succeeded
Configuration validation succeeded
amazon-cloudwatch-agent start/running, process NNNNNN
```

エージェントを停止したい場合には、以下のように実行します。

```bash
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a stop
```

## カスタムメトリクスの確認

CloudWatchにカスタムメトリクスが追加されているか確認します。
CWAgentという名前空間のカスタムメトリクスが作成されていれば成功です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106949/89b3dd4f-de79-a1c2-6b00-b52972318334.png)

# 参考URL

- [新しいCloudWatch Agentでメトリクスとログの収集が行なえます](https://dev.classmethod.jp/cloud/aws/new-cloudwatch-agent-collect-metrics-and-logs/)
- [新しいCloudWatch AgentでEC2インスタンスのメモリ使用率を監視する](https://qiita.com/hayao_k/items/d983177510b3b3a69561)
- [EC2 をIAMユーザ/アクセスキーからIAM Roleへ移行する手順を検証](https://dev.classmethod.jp/cloud/aws/ec2-iam-user-to-iam-role/)