Amazon CloudWatch を使って Windows のカスタムメトリクスを設定してみた

どうも、クラウドエンジニアのオタユウ（[@yu40ta_engineer](https://twitter.com/yu40ta_engineer)）です。

業務柄、システム構築の過程で監視設定を行うことが多く、カスタムメトリクスをいじくり回す機会があったので、検証したことを自分の備忘録がてら記事にしておきます。

#本記事のゴール
「カスタムメトリクスの前提条件を知ることで、カスタムメトリクスを取得できないときの勘どころを知っていただくこと」でございます。
今回は、実際に起こった事例をもとにした検証内容をご紹介します。

#１．起こっていた問題
Amazon標準AMIで立ち上げた Windows 2016 の EC2インスタンス から カスタムメトリクス が取得できていない。CloudWatchに表示されていない。

同一アカウント内の他のインスタンスや他のお客様のアカウント内のインスタンスでは、カスタムメトリクスが正しく取得できているのに関わらず、一部のインスタンスのみ上手く表示されていない。
困った。さて、どうしよう。

##使用する主要サービス

<ul>
  <li>EC2</li>
  <li>IAM</li>
  <li>AWS Systems Manager（以下、SSM）</li>
  <li>CloudWatch</li>
</ul>

##前提条件(確認しておきたい点）

下記の4つです。

<ul>
  <li><strong>実行するEC2にIAMの管理ポリシー「AmazonEC2RoleforSSM」がアタッチされているロールが割り当てられているか？</strong></li>
  <li><strong>SSMエージェントがインストールされており、起動している状態か？（※1）</strong></li>
  <li><strong>EC2からインターネットに接続可能か？プライベート接続の場合はエンドポイントを使用しているか？（※2）</strong></li>
  <li><strong>SSMのランコマンドで実行する「JSONの構文」は正しく記述されているか？</strong></li>
</ul>
※1 SSMエージェントがプリインストールされているAMIについては、AWS公式ドキュメントの <a href="https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/ssm-agent.html">SSM エージェント の使用</a> をご確認ください。SSMエージェントがプリインストールされていないAMIへのインストールについても記載されています。

※2 プライベート接続の場合は下記のVPCエンドポイントが必須です。

<ul>
  <li>com.amazonaws.ap-northeast-1.ssm</li>
  <li>com.amazonaws.ap-northeast-1.ec2messages</li>
  <li>com.amazonaws.ap-northeast-1.monitoring</li>
</ul>

要は「カスタムメトリクスを取得するための適切な設定ができていますか？」ということです。
今回はVPCエンドポイントは使用せず、インターネットアウトする形で検証します。

#２．カスタムメトリクスとは？

前提知識として、そもそもカスタムメトリクスって何？という方向けです。
もう知ってるよ！という方は読み飛ばしていただいて構いません。

カスタムメトリクスとは、EC2インスタンスに対する監視（モニタリング）において、CloudWatchの<a href="https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-cloudwatch.html">標準モニタリング（5分間隔/無償）</a>および<a href="https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-cloudwatch-new.html">詳細モニタリング（1分間隔/有償）</a>以外で、独自に設定できる監視項目設定のことです。
SSMエージェントとCloudWatchエージェントをEC2インスタンスにインストールすることで、EC2インスタンスのOS情報からユーザー自身で定義したメトリクス（＝カスタムメトリクス）を収集できるようになります。

##CloudWatchの標準または詳細モニタリングにおける監視項目

<ul>
  <li>CPU使用率</li>
  <li>ディスクI/O</li>
  <li>ネットワークI/O</li>
  <li>ステータスチェック（EC2稼働状態）</li>
</ul>

##カスタムメトリクスの監視設定可能な項目

<ul>
  <li>CPU詳細</li>
  <li>ディスク詳細</li>
  <li>メモリ使用率</li>
  <li>ネットワーク詳細</li>
  <li>プロセス情報</li>
</ul>

一般的によく利用されているものだと「ディスク使用量」や「メモリ使用率」の監視が挙げられます。
カスタムメトリクスを設定しておくことで、より詳細にリソースの監視ができるというわけですね。

それでは、実際の設定に移っていきましょう。

#３．検証の流れ

冒頭でお伝えした通り、カスタムメトリクスの設定において考慮すべき点は以下の4つです。

<ul>
  <li><strong>実行するEC2にIAMの管理ポリシー「AmazonEC2RoleforSSM」がアタッチされているロールが割り当てられているか？</strong></li>
  <li><strong>EC2からインターネットに接続可能か？プライベート接続の場合はエンドポイントを使用しているか？</strong></li>
  <li><strong>SSMエージェントがインストールされており、起動している状態か？</strong></li>
  <li><strong>SSMのランコマンドで実行する「JSONの構文」は正しく記述されているか？</strong></li>
</ul>

この4点さえ守れていれば、正しくカスタムメトリクスが取得できます。
なお、使用するサービスは4つでした。

<ul>
  <li>EC2</li>
  <li>IAM</li>
  <li>SSM</li>
  <li>CloudWatch</li>
</ul>

EC2とIAMロールは既に作成している前提で進めます。
さっそく操作手順を見ていきましょう。

###EC2の確認

![1_ssmroleなしEC2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/7858ee16-59f7-abc5-54f8-ea584f24488c.png)

まだSSM用のIAMロールは割り当てられていません。

###IAMロール（IAMの管理ポリシー「AmazonEC2RoleforSSM」がアタッチされているロール）をEC2に割当

![2_ssmrole割り当て.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/373bf382-0b07-f524-1afb-7aeb14c19c69.png)

![2-1_ssmrole割り当て.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/915170a9-e809-1d2e-ec27-2f671f33daaa.png)

![2-2_ssmrole割り当て.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/3ceac351-cdbe-6803-9fb8-7caacf6ab9da.png)

![3_ssmrole割り当て済EC2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/6106397c-2ba3-1ab7-cecb-4f9201a58a69.png)

無事にSSM用のIAMロールが割り当てられました。
念のため補足ですが、キャプチャのIAMロール名は私がIAMロールを作成した時に適当に命名したもので、
中身はIAMの管理ポリシー「AmazonEC2RoleforSSM」がアタッチされているものです。

###SSMのマネージドインスタンスを確認

![4_managed-instance化.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/214f5ef9-a0cd-88c1-04f8-73fcef0e0a86.png)

SSMエージェントがプリインストールされているAMIであれば、IAMロールを割り当て後にSSMエージェントが自動起動され、SSMのマネージドインスタンスとして表示されます。
プリインストールされていないAMIの場合は、OSにRDP接続し、SSMエージェントインストール後に手動起動または再起動する必要があります。

ちなみにマネージドインスタンスとして表示されたEC2のIAMロールを外すと、SSMのサービス画面上にこのような警告が表示されます。

![4-3_ssmrole外したときの警告.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/e51b6474-6af4-c5d4-a99f-4251e6ec13fe.png)

マネージドインスタンス化したEC2インスタンスは、SSMのセッションマネージャー等で動作確認しておくことをオススメします。

こんな感じで。

![4-1_session-managerで動作確認.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/02acee1a-98dc-fdda-27dd-28831c47f775.png)

![4-2_session-managerで動作確認.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/3a02f3fc-a60b-8e7e-25d9-f19a12d6d505.png)

###SSMランコマンドの実行

マネージドインスタンス→[アクション]から[コマンド実行]を選択

![5_ssm_custommetrics_runcommand.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/a1c772cb-ff22-bd3d-52b0-ea44b50e5a0c.png)

「AWS-ConfigureCloudWatch」を選択

![5-1_ssm_custommetrics_runcommand_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/4cbd2e91-92b1-5ccd-f6e0-a1fd70992924.png)

ランコマンドを実行するインスタンスを選択

![5-2_ssm_custommetrics_runcommand_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/a6b02d66-989d-129d-d273-3528c90e3dbc.png)

カスタムメトリクス用のJSONを記述（※後で一部ご紹介します）

![5-3_ssm_custommetrics_runcommand_4.png.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/a36384bf-ceb0-0e2e-660d-65a507cfd188.png)

実行！

![5-4_ssm_custommetrics_runcommand_check.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/3897f6b7-75c1-1d16-a75d-710f69e343b2.png)

早速CloudWatchのメトリクスを確認してみましょう。

![6_CloudWatch確認_失敗.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/3557e45b-9ea0-5cea-1332-828c3672844a.png)

・
・
・
・
・
・
・
・
・
・

待てど暮らせど、カスタムメトリクスは表示されない。
全ての手順はクリアしているはず。何故なのか。

#４．AWSサポートに問い合わせたこと

問題切り分けのため、AWSサポートに以下のことを問い合わせました。

<ul>
  <li>インスタンス自体に問題がないか？</li>
→問題なし。
  <li>SSMエージェントやCloudWatchエージェントは正しく起動しているか？</li>
→問題なく起動していました。
  <li>接続設定に問題がないか？（プロキシやプライベート接続が起因しないか）</li>
→EC2インスタンスがインターネットアウトできる、かつSSMエージェントおよびCloudWatchエージェントが起動していれば、CloudWatchエンドポイントにアクセスできるので問題なし。
</ul>

…となるとあとはJSON、お前か。

#５．JSONの構文チェック

ここではJSONの中身の詳細説明は割愛し、問題の箇所のみピックアップします。
しかし、目視で構文チェックをするのはとっても骨が折れますので、すぐに構文チェックサイトを頼りましょう。

<img width="1407" alt="json_error.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/d29a24ed-a307-c7e1-b340-2b2208516055.png">

おや……？
エラーが出ました。ここでようやく、構文内（キャプチャ箇所）に不自然なスペースがあることに気付きます。
修正すると、、、

<img width="1413" alt="json_success.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/63dee527-bf72-54ae-91aa-16f73f7b1fca.png">

エラーが解消されました！
それでは、もう一度AWSに戻ってSSMランコマンドを実行してから、CloudWatchのメトリクスを確認してみましょう。

![7_CloudWatch確認_成功.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/8998c47a-e5b7-aa70-265d-8f287023919d.png)

![7-1_CloudWatch確認_成功.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347034/45e731d1-6ffb-b112-de59-7abec53d060c.png)

無事にカスタムメトリクスが表示されました。めでたしめでたし。
JSONで指定したNameSpaceやメトリクス名が表示されていることが確認できます。

さいごに、使用したJSONを置いておきます。
検証キャプチャでは NameSpace を Custom metrics としていましたが、JSON的には気持ちが悪いのでキャメルケースに修正し、また、表記上Windowsのカスタムメトリクスだということが分かりやすいように変更を加えました。

```
{
	"IsEnabled": true,
	"EngineConfiguration": {
		"PollInterval": "00:05:00",
		"Components": [
			{
				"Id": "PerformanceCounterDiskSpaceUtilizationC",
				"FullName": "AWS.EC2.Windows.CloudWatch.PerformanceCounterComponent.PerformanceCounterInputComponent,AWS.EC2.Windows.CloudWatch",
				"Parameters": {
					"CategoryName": "LogicalDisk",
					"CounterName": "% Free Space",
					"InstanceName": "C:",
					"MetricName": "DiskFreeC",
					"Unit": "Percent",
					"DimensionName": "InstanceId",
					"DimensionValue": "{instance_id}"
				}
			},
			{
				"Id": "CloudWatch",
				"FullName": "AWS.EC2.Windows.CloudWatch.CloudWatch.CloudWatchOutputComponent,AWS.EC2.Windows.CloudWatch",
				"Parameters": {
					"AccessKey": "",
					"SecretKey": "",
					"Region": "ap-northeast-1",
					"NameSpace": "CustomMetrics/Windows"
				}
			}
		],
		"Flows": {
			"Flows": [
				"(PerformanceCounterDiskSpaceUtilizationC),CloudWatch"
			]
		}
	}
}
```

#６．検証結果

初歩的な問題でしたが、JSONの構文エラーが起きておりました。
JSONのコピー＆ペースト時に何らかの形で余計な空白が挿入されてしまっていたようです。

注意すべきは、<strong>JSONの構文エラーがあっても SSM Run Command ではエラーを吐いてくれない</strong>点です。
そのため、事前に JSON構文チェック を行い、正しい記述であることを確認した上でのランコマンド実行をオススメします。
エンジニアとしての基本中の基本を改めて教わった気持ちになりました（汗

以上！ご拝読ありがとうございました。