CloudWatchでCentOS7系EC2インスタンスのメモリ使用率とディスク使用率とプロセスを監視する

# はじめに

`CentOS7`系`EC2`インスタンスの`CloudWatch`監視を設定する機会があったのでメモとして残しておきます。
まず、AWSの[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/mon-scripts.html)によると旧来の `CloudWatch モニタリングスクリプトを使用したメトリクスの収集` は **非推奨** とのことです。
`CloudWatchモニタリングスクリプト`では**サポート対象外だった**`CentOS7`ですが、`CloudWatchAgent`では**サポート対象**となっているため`CloudWatchAgent`を使いましょう。

# 監視設定

## `EC2`インスタンスに`CloudWatch`へのアクセス権限を付与する

[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/mon-scripts.html)によると

> 次の例では、IAM ロールまたは awscreds.conf ファイルを指定していることを前提としています。それ以外の場合は、これらのコマンドで --aws-access-key-id および --aws-secret-key パラメータを使用して認証情報を指定する必要があります。

と記載されていますが、AWSのリソースに対する権限付与の場合は`IAMロール`で設定するのが良いと思います。
というわけで、`EC2`インスタンスの`IAMロール`には以下の`IAMポリシー`をアタッチしておきます。

* CloudWatchAgentServerPolicy
* CloudWatchAgentAdminPolicy

また、`IAMポリシー`を作成後、`EC2`インスタンスへのアタッチを忘れずに実施しましょう。
**※この辺の操作は割愛します。**

## `CloudWatchAgent`のインストール

```bash:CloudWatchAgentのインストールコマンド
$ sudo yum install https://s3.amazonaws.com/amazoncloudwatch-agent/centos/amd64/latest/amazon-cloudwatch-agent.rpm
```

## 監視項目の設定

以下のコマンドで監視項目設定のウィザードを起動し、必要な監視項目を設定します。

```bash:CloudWatchAgent設定ファイル作成ウィザード起動コマンド
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
```

以下の様に、設定項目毎に表示された `[番号]+[Enterキー]` もしくは `[Enterキー]` を押していきます。

```bash:設定例
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
=============================================================
= Welcome to the AWS CloudWatch Agent Configuration Manager =
=============================================================
# インストール対象のOS種別を選択する
On which OS are you planning to use the agent?
1. linux
2. windows
default choice: [1]:

# EC2かオンプレミスかを選択する
Trying to fetch the default region based on ec2 metadata...
Are you using EC2 or On-Premises hosts?
1. EC2
2. On-Premises
default choice: [1]:

# CloudWatchAgentを実行するユーザを指定する
Which user are you planning to run the agent?
1. root
2. cwagent
3. others
default choice: [1]:

# statusdをオンにするかどうか
Do you want to turn on StatsD daemon?
1. yes
2. no
default choice: [1]:

# statusdのリッスンポートを指定する
Which port do you want StatsD daemon to listen to?
default choice: [8125]

# statusdデーモンがメトリクスを収集する間隔を指定する
What is the collect interval for StatsD daemon?
1. 10s
2. 30s
3. 60s
default choice: [1]:

# statusdが収集したメトリクスの集計間隔を指定する
What is the aggregation interval for metrics collected by StatsD daemon?
1. Do not aggregate
2. 10s
3. 30s
4. 60s
default choice: [4]:

# collectdによるメトリクス監視を行うか
Do you want to monitor metrics from CollectD?
1. yes
2. no
default choice: [1]:
2

# ホストのメトリクスを監視するか
Do you want to monitor any host metrics? e.g. CPU, memory, etc.
1. yes
2. no
default choice: [1]:

# コアごとのCPUメトリクスを監視するか
Do you want to monitor cpu metrics per core? Additional CloudWatch charges may apply.
1. yes
2. no
default choice: [1]:

# 情報が利用可能であれば全てのメトリクスにEC2ディメンションを追加するか
Do you want to add ec2 dimensions (ImageId, InstanceId, InstanceType, AutoScalingGroupName) into all of your metrics if the info is available?
1. yes
2. no
default choice: [1]:

# メトリクスを高解像度で収集するか
Would you like to collect your metrics at high resolution (sub-minute resolution)? This enables sub-minute resolution for all metrics, but you can customize for specific metrics in the output json file.
1. 1s
2. 10s
3. 30s
4. 60s
default choice: [4]:

# どのデフォルトのメトリクス設定にするか
Which default metrics config do you want?
1. Basic
2. Standard
3. Advanced
4. None
default choice: [1]:

# 現在の設定
Current config as follows:
{
	"agent": {
		"metrics_collection_interval": 60,
		"run_as_user": "root"
	},
	"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
			},
			"statsd": {
				"metrics_aggregation_interval": 60,
				"metrics_collection_interval": 10,
				"service_address": ":8125"
			}
		}
	}
}

# 上記の設定で問題ないかどうかの確認メッセージ
Are you satisfied with the above config? Note: it can be manually customized after the wizard completes to add additional items.
1. yes
2. no
default choice: [1]:

# 移行のためにインポートする既存のCloudWatchLogAgentの設定ファイルがあるかどうか
Do you have any existing CloudWatch Log Agent (http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AgentReference.html) configuration file to import for migration?
1. yes
2. no
default choice: [2]:

# ログファイルを監視するか
Do you want to monitor any log files?
1. yes
2. no
default choice: [1]:
2

# 設定を /opt/aws/amazon-cloudwatch-agent/bin/config.json に保存した旨のメッセージ
Saved config file to /opt/aws/amazon-cloudwatch-agent/bin/config.json successfully.
Current config as follows:
{
	"agent": {
		"metrics_collection_interval": 60,
		"run_as_user": "root"
	},
	"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
			},
			"statsd": {
				"metrics_aggregation_interval": 60,
				"metrics_collection_interval": 10,
				"service_address": ":8125"
			}
		}
	}
}

# コンフィグをSSMパラメータストアに保存するか
Please check the above content of the config.
The config file is also located at /opt/aws/amazon-cloudwatch-agent/bin/config.json.
Edit it manually if needed.
Do you want to store the config in the SSM parameter store?
1. yes
2. no
default choice: [1]:

# パラメータストアに保存する名前を選択する
What parameter store name do you want to use to store your config? (Use 'AmazonCloudWatch-' prefix if you use our managed AWS policy)
default choice: [AmazonCloudWatch-linux]

# EC2のメタデータに基づきデフォルトのリージョンを確認するメッセージ
Trying to fetch the default region based on ec2 metadata...
Which region do you want to store the config in the parameter store?
default choice: [ap-northeast-1]

# パラメータストアに設定ファイルを送信するためのクレデンシャル確認メッセージ
Which AWS credential should be used to send json config to parameter store?
1. ASIA****************(From SDK)
2. Other
default choice: [1]:

Successfully put config to parameter store AmazonCloudWatch-linux.
Program exits now.
```

## `CloudWatchAgent`の起動

以下のコマンドでエージェントを起動します。
`fetch-config`オプションがついていることで、`パラメータストア`から最新の設定を取得して起動するようです。
※`systemctl`コマンドでも起動できますが、オフィシャルのドキュメントではこちらのコマンドを推奨しているようでした

```bash:CloudWatchAgentの起動コマンド
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c ssm:AmazonCloudWatch-linux -s
```

## メトリクス送信状況の確認

`CloudWatch`の`メトリクス`のうち、`CloudWatchAgent`のメトリクスは以下のパスに存在します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158971/1c4ee466-f2fc-5e95-e411-9e899236776c.png)

`ディスク使用率`や`CPU使用率`、`メモリ使用率`でメトリクスが書き出されるページが異なるので、必要に応じて確認しましょう。
**※実際にメトリクスがグラフとして表示されるまでには暫くかかります**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158971/7404e5e6-6fe1-703c-7061-4c3c3aa7f524.png)

## プロセス監視設定を追加する場合

個別にプロセス監視設定を追加したい場合は、パラメータストアに保存された設定に以下の様に追記します。

```json:mysqlプロセス監視の例
{
  "metrics": {
    "metrics_collected": {
      "procstat": [
        {
          "exe": "mysql",
          "measurement": [
            "pid_count"
          ],
          "metrics_collection_interval": 60
        }
      ]
    }
  }
}
```

保存した後、サーバ側で`fetch-config`オプションを付けて最新の設定ファイルを詠み込ませるのを忘れずに。

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

## ダッシュボードの作成

必要なメトリクスが`CloudWatch`に送られていることが一通り確認できたら、ダッシュボードを作成しましょう。
`CPU使用率`,`ディスク使用率`,`メモリ使用率`などは`線グラフ`が見やすいですが、`プロセス監視`の場合は`数値`表示にしておくと見やすいかもしれません。
**※この辺の操作は割愛します。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158971/5bf9bd64-1e18-c5a1-eb8f-99137377d5bb.png)

## アラームの設定

各メトリクスの値が閾値を越えたらアラームが鳴るように適宜設定しましょう。
操作については割愛しますが、最低限`CPU使用率`,`メモリ使用率`,`ディスク使用率`は監視しておいた方が良いと思います。
また、`t3.micro`など`T`系インスタンスファミリを使用している場合、**CPUバーストによりCPUクレジットが枯渇する場合がある**ので関連するメトリクスを監視しておくのが良いでしょう。

# トラブルシューティング

## `CloudWatchAgent`の起動に失敗する

```bash:エラーメッセージ
======== Error Log ========
2020-10-23T01:01:11Z E! [telegraf] Error running agent: Error parsing /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml, open /usr/share/collectd/types.db: no such file or directory
```

ウィザードでエージェントの設定を行う際、 `collectd` を使った監視項目を有効にするとエージェントの起動に失敗します。

```bash:ウィザードでcollectdの監視項目を使用するか聞かれる項目
Do you want to monitor metrics from CollectD?
1. yes
2. no
default choice: [1]:
```

原因としては、`collectd`が入っていない事なので、`collectd`の監視項目が必要な場合は[collectd を使用したカスタムメトリクスの取得](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-custom-metrics-collectd.html)を参考に `collectd` をインストールしましょう。
※`SWAP`の監視など、監視したい項目によっては必要になるものなので用途に応じてインストールしましょう。

```bash
$ sudo yum install collectd
```

# 参考

* [小ネタ]Amazon Linux 2 で CloudWatch エージェントを起動しようとしてハマった話
    * https://dev.classmethod.jp/articles/amazon-linux-2-cloudwatch-agent-error-solution/
* 新しいCloudWatch AgentでEC2インスタンスのメモリ使用率を監視する
    * https://qiita.com/hayao_k/items/d983177510b3b3a69561#agent-%E8%A8%AD%E5%AE%9A
* EC2上のプロセスを監視し自動復旧する
    * https://dev.classmethod.jp/articles/cloudwatchagent-process-monitor-action/