Amazon Systems Manager 経由でEC2にCloudWatch agent を設定する

# 概要
Amazon Systems Manager を利用して1台以上のEC2 インスタンスにCloudWatch Agent をインストールを行います。その後、Parameter Store に保存した設定ファイル(config.json) を利用して、EC2に設定ファイルを配布します。
[CloudWatch エージェントを使用して Amazon EC2 インスタンスとオンプレミスサーバーからメトリクスとログを収集する]
(https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html) についての話です。

# 手順
## 概要
以下の手順で行っていきます。
1. IAMロールを作成し、インスタンスにアタッチ
2. Systems Manager 経由でCloudWatch をインストール
3. CloudWatch-agent-config-wizard を利用して設定ファイルを作成し、Parameter Store にアップロード
4. アップロードしたパラメータを利用して、各EC2 インスタンスに対して設定ファイルを配布

## 設定
**IAMロールを作成し、インスタンスにアタッチ**
以下のPolicy をアタッチしたIAM ロールを作成し、インスタンスにアタッチします。
- CloudWatchAgentServerPolicy
- AmazonSSMManagedInstanceCore
- ssm:PutParameter を許可したインラインポリシー（後で削除します）

**Systems Manager 経由でCloudWatch をインストール**
SSMエージェントがプリインストールされたAMIを利用していない場合は、ssm-agent をインストールする必要があります。その場合は[ハイブリッド環境で AWS Systems Manager を設定する](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-managedinstances.html) を参考にインストールを行います。

Systems Manager の*Run Command* を利用してcloudwatch-agent をインストールします。
実行するドキュメントは `AWS-ConfigureAWSPackage` です。パラメータは以下をセットします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250213/e041fd89-60a6-fa0c-19fa-bd14366c9bd4.png)

ターゲットインスタンスを指定して実行します。*インスタンスを手動で選択する* を選択すると、今回作成したインスタンスが表示されています。表示されていない場合は、IAMロールの設定か、インスタンスからSystems Manager のエンドポイントへのアクセスができないなどが考えられます。

成功するとインスタンスにcloudwatch-agent がインストールされます。

**CloudWatch-agent-config-wizard を利用して設定ファイルを作成し、Parameter Store にアップロード**
CloudWatch のagent-config の作成方法は2つあります。
1. ウィザードを使用して CloudWatch エージェント設定ファイルを作成する
2. CloudWatch エージェント設定ファイルを手動で作成または編集する
1を利用して、設定ファイルを作成します。

```
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
```
を実行して、対話式に設定ファイルを作成すると以下のものが作成されます。

```
{
   "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":{
         "collectd":{
            "metrics_aggregation_interval":60
         },
         "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"
         }
      }
   }
}
```

最後にParameter Store にアップロードするかどうか聞かれるので名前を決めてアップロードします。この時にIAMロールにアタッチした `ssm:PutParameter` が必要になります。アップロードが済んだら`ssm:PutParameter` は不要です。

**アップロードしたパラメータを利用して、各EC2 インスタンスに対して設定ファイルを配布**
最後にParameter Store にアップロードした設定ファイルを`Run Command` を利用してインスタンスに配布します。
ドキュメントは `AmazonCloudWatch-ManageAgent` を利用し、Optional Configuration Location にはParameter store の名前を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250213/f4d2c769-694b-025e-81ec-cf27015448d3.png)

実行すると、`/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/ssm__AmazonCloudWatch-linux` に配布されます。

必要に応じて `AmazonCloudWatch-ManageAgent` ドキュメントを利用してCloudWatch-agent を再起動したり、`AWS-RunShellScript` ドキュメントを利用して collectd をインストールしたりします。

**CloudWatch メトリクスを確認**
CloudWatch メトリクスを見ると *CWAgent* というカスタム名前空間ができています。そこを確認するとディスク使用率が表示されていることを確認できます。

# 最後に
Parameter Store に格納した設定ファイルを更新して、*Run Command* で配布するということができるようになりました。デフォルトのままだとモニタリングしたい箇所がとれないということがあると思うので、その場合は、[CloudWatch エージェント設定ファイルを手動で作成または編集する](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html)を参考に修正して、*Run Command* で配布することができます。また、*Run command* ではインスタンスIDだけではなく、タグ名でも指定することができるので、使い方次第で運用が非常に楽になります。

メトリクスごとに料金がかかるので[料金の計算](https://aws.amazon.com/jp/cloudwatch/pricing/)を利用するとメトリクス数でどれくらい料金がかかるのかの試算をすることができます。