今回は、Amazon EC2 Windows インスタンスのシステムリソース監視、状態監視、イベントログモニタリング、異常時のアラート通知までを Amazon CloudWatch を利用して一元的に AWS CDK で実装する方法をまとめました。
はじめに
今回は、Windows EC2インスタンスの包括的な監視システムをAWS CDKで実装していきます。システムリソース監視、死活監視、プロセス監視、Windowsイベントログ監視まで、運用に必要な監視項目を実装します。
また、今回は既に構築されているEC2のインスタンスIDを指定して監視設定を追加していきます。
今回作成するリソース
- SNSトピック: CloudWatchアラームの通知先
- CloudWatchアラーム: システム/インスタンス死活監視、リソース使用率監視、プロセス監視
- CloudWatch Logs: Windowsイベントログ収集とエラー監視
- メトリクスフィルター: イベントログのエラーパターン検出
アーキテクチャ概要
AWS CDK ソースコード
インスタンスIDインポート
const ec2Instance = 'i-xxxxxxxxxxxxxxxxx' // 監視対象のインスタンスIDを指定
SNS通知設定
const emailAddresses = [ // SNS通知先メーリングリスト(通知先が複数ある場合アドレスを追加)
'xxxxxx@example.com',
'xxxxxxx@example.com',
];
// CloudWatchアラーム用トピック
const alarmTopic = new sns.Topic(this, 'AlarmTopic', {
topicName: 'clw-alertnotification', // トピック名
displayName: 'Cloudwatch Alert Notifications' // 表示名
});
// CloudWatchアラーム用サブスクリプション
emailAddresses.forEach(email => {
alarmTopic.addSubscription(
new subscriptions.EmailSubscription(email) // プロトコル:EMAIL
);
});
ポイント:
- 複数の管理者への通知配信
- アラーム発生時に通知するメールアドレスを指定
CloudWatchアラーム設定
システム死活監視
const statusCheckFailedSystemAlarm = new cloudwatch.Alarm(this, 'StatusCheckFailedSystemAlarm', {
alarmName: 'alarm-ec2-scfs',
metric: new cloudwatch.Metric({
namespace: 'AWS/EC2',
metricName: 'StatusCheckFailed_System', // メトリクス名
dimensionsMap: {
InstanceId: ec2Instance,
},
statistic: 'sum', // 統計:合計
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値(1以上=失敗あり)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
statusCheckFailedSystemAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
statusCheckFailedSystemAlarm.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
インスタンス死活監視
const statusCheckFailedInstanceAlarm = new cloudwatch.Alarm(this, 'StatusCheckFailedInstanceAlarm', {
alarmName: 'alarm-ec2-scfi',
metric: new cloudwatch.Metric({
namespace: 'AWS/EC2',
metricName: 'StatusCheckFailed_Instance', // メトリクス名
dimensionsMap: {
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID
},
statistic: 'sum', // 統計:合計
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値(1以上=失敗あり)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
statusCheckFailedInstanceAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
statusCheckFailedInstanceAlarm.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
CPU使用率監視
const cpuAlarm = new cloudwatch.Alarm(this, 'CpuAlarm', {
alarmName: 'alarm-ec2-cpu',
metric: new cloudwatch.Metric({
namespace: 'AWS/EC2',
metricName: 'CPUUtilization', // メトリクス名
dimensionsMap: {
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID
},
statistic: 'Average', // 統計:平均
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 90, // アラームの閾値(CPU使用率90%)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
cpuAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
cpuAlarm.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
メモリ使用率監視
const memoryAlarm = new cloudwatch.Alarm(this, 'MemoryAlarm', {
alarmName: 'alarm-ec2-mem',
metric: new cloudwatch.Metric({
namespace: 'CWAgent',
metricName: 'Memory % Committed Bytes In Use', // メトリクス名
dimensionsMap: { // 取得に必要な変数
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID(config.jsonのappend_dimensionsで指定)
objectname: 'Memory' // オブジェクト名(config.jsonのmetrics_collectedで指定)
},
statistic: 'Average', // 統計:平均
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 90, // アラームの閾値(メモリ使用率90%)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
memoryAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
memoryAlarm.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
ディスク使用率監視
const diskAlarmC = new cloudwatch.Alarm(this, 'DiskAlarmC', {
alarmName: 'alarm-ec2-dsk-c',
metric: new cloudwatch.Metric({
namespace: 'CWAgent',
metricName: 'LogicalDisk % Free Space', // メトリクス名
dimensionsMap: {
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID(config.json側のappend_dimensionsで指定)
instance: 'C:', // 対象ディスク
objectname: 'LogicalDisk' // オブジェクト名(config.json側のmetrics_collectedで指定)
},
statistic: 'Average', // 統計:平均
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 10, // アラームの閾値
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD, // アラーム条件: より小さい
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
diskAlarmC.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
diskAlarmC.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
ディスク使用率監視(Dドライブ)
const diskAlarmD = new cloudwatch.Alarm(this, 'diskDAlarmD', {
alarmName: 'alarm-ec2-dsk-d',
metric: new cloudwatch.Metric({
namespace: 'CWAgent',
metricName: 'LogicalDisk % Free Space', // メトリクス名
dimensionsMap: {
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID(config.json側のappend_dimensionsで指定)
instance: 'D:', // 対象ディスク
objectname: 'LogicalDisk' // オブジェクト名(config.json側のmetrics_collectedで指定)
},
statistic: 'Average', // 統計:平均
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 10, // アラームの閾値
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD, // アラーム条件: より小さい
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
diskAlarmD.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
diskAlarmD.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
プロセス監視
const svchostServiceAlarm = new cloudwatch.Alarm(this, 'SVCHostServiceAlarm', {
alarmName: 'alarm-svchost',
metric: new cloudwatch.Metric({
namespace: 'CWAgent',
metricName: 'procstat_lookup pid_count', // メトリクス名(プロセスに関連付けられたプロセスIDの数)
dimensionsMap: {
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID(config.json側のappend_dimensionsで指定)
exe: 'svchost.exe', // 監視対象のプロセス名
pid_finder: 'native' // プロセスの検出方法:native(OSのネイティブAPIを使用)
},
statistic: 'Min', // 統計: 最小
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.LESS_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件:閾値以下
treatMissingData:
cloudwatch.TreatMissingData.BREACHING, // 欠落データを不正(しきい値を超えている)として処理
});
svchostServiceAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
svchostServiceAlarm.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
イベントログ(システムログ)用のロググループのエラー監視
// イベントログ(システムログ)用のロググループのエラー監視アラーム
const sytemLogErrorsAlarm = new cloudwatch.Alarm(this, 'SystemLogErrorsAlarm', {
alarmName: 'os-eventlog-system',
metric: new cloudwatch.Metric({
namespace: 'os-cloudwatchlogs', // カスタムメトリクスの名前空間(CloudwachLogsで作成した名前空間を指定)
metricName: 'OS-Eventlog-System', // メトリクス名
statistic: 'Sum', // 統計:合計
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値(1以上=失敗あり)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
sytemLogErrorsAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
ポイント:
- 名前空間: システムロググループの名前空間を指定
- メトリクス名: システムロググループのメトリクス名を指定
イベントログ(アプリケーションログ)用のロググループのエラー監視
// イベントログ(アプリケーションログ)用のロググループのエラー監視アラーム
const appLogErrorsAlarm = new cloudwatch.Alarm(this, 'ApplicationLogErrorsAlarm', {
alarmName: 'os-eventlog-application',
metric: new cloudwatch.Metric({
namespace: 'os-cloudwatchlogs', // カスタムメトリクスの名前空間(CloudwachLogsで作成した名前空間を指定)
metricName: 'OS-Eventlog-Application', // メトリクス名
statistic: 'Sum', // 統計:合計
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値(1以上=失敗あり)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
appLogErrorsAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
ポイント:
- 名前空間: アプリケーションロググループの名前空間を指定
- メトリクス名: アプリケーションロググループのメトリクス名を指定
イベントログ(セキュリティ)用のロググループのエラー監視
// イベントログ(セキュリティログ)用のロググループのエラー監視アラーム
const securityLogErrorsAlarm = new cloudwatch.Alarm(this, 'SecurityLogErrorsAlarm', {
alarmName: 'os-eventlog-security',
metric: new cloudwatch.Metric({
namespace: 'os-cloudwatchlogs', // カスタムメトリクスの名前空間(CloudwachLogsで作成した名前空間を指定)
metricName: 'OS-Eventlog-Security', // メトリクス名
statistic: 'Sum', // 統計:合計
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値(1以上=失敗あり)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
securityLogErrorsAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
ポイント:
- 名前空間: イベントロググループの名前空間を指定
- メトリクス名: イベントロググループのメトリクス名を指定
CloudWatch Logs設定
ロググループとメトリクスフィルター
// OSイベントログ(システムログ)用のロググループ
const systemLogGroup = new logs.LogGroup(this, 'SystemLogGroup', {
logGroupName: 'loggroup-os-eventlog-system',
retention: logs.RetentionDays.ONE_MONTH, // 保持期間: 1ヵ月
removalPolicy: cdk.RemovalPolicy.DESTROY
});
const systemErrorMetricFilter = new logs.MetricFilter(this, 'SystemErrorMetricFilter', { // イベントログ(システムログ)用メトリクスフィルター
logGroup: systemLogGroup,
filterName: 'filter-os-eventlog-system', // フィルター名
filterPattern: logs.FilterPattern.literal('?ERROR ?Error ?error ?FAIL ?Fail ?fail'), // フィルターパターン
metricNamespace: 'os-cloudwatchlogs', // メトリクス名前空間
metricName: 'OS-Eventlog-System', // メトリクス名
metricValue: '1', // メトリクス値
defaultValue: 0
});
// OSイベントログ(アプリケーションログ)用のロググループ
const applicationLogGroup = new logs.LogGroup(this, 'ApplicationLogGroup', {
logGroupName: 'loggroup-os-eventlog-application',
retention: logs.RetentionDays.ONE_MONTH, // 保持期間: 1ヵ月
removalPolicy: cdk.RemovalPolicy.DESTROY
});
const applicationErrorMetricFilter = new logs.MetricFilter(this, 'ApplicationErrorMetricFilter', { // イベントログ(アプリケーションログ)用メトリクスフィルター
logGroup: applicationLogGroup,
filterName: 'filter-os-eventlog-application', // フィルター名
filterPattern: logs.FilterPattern.literal('?ERROR ?Error ?error ?FAIL ?Fail ?fail'), // フィルターパターン
metricNamespace: 'os-cloudwatchlogs', // メトリクス名前空間
metricName: 'OS-Eventlog-Application', // メトリクス名
metricValue: '1', // メトリクス値
defaultValue: 0
});
// OSイベントログ(セキュリティログ)用のロググループ
const securityLogGroup = new logs.LogGroup(this, 'SecurityLogGroup', {
logGroupName: 'loggroup-os-eventlog-security',
retention: logs.RetentionDays.ONE_MONTH, // 保持期間: 1ヵ月
removalPolicy: cdk.RemovalPolicy.DESTROY
});
const securityErrorMetricFilter = new logs.MetricFilter(this, 'SecurityErrorMetricFilter', { // イベントログ(セキュリティログ)用メトリクスフィルター
logGroup: securityLogGroup,
filterName: 'filter-os-eventlog-security', // フィルター名
filterPattern: logs.FilterPattern.literal('?ERROR ?Error ?error ?FAIL ?Fail ?fail'), // フィルターパターン
metricNamespace: 'os-cloudwatchlogs', // メトリクス名前空間
metricName: 'OS-Eventlog-Security', // メトリクス名
metricValue: '1', // メトリクス値
defaultValue: 0
});
}
}
ポイント:
- ログ種別: System、Application、Securityの3種類
- メトリクスフィルター: ERROR/Error/error/FAIL/Fail/failパターンを検出
- 保持期間: 1ヶ月(要件に応じて調整可能)
- 本番環境では:
removalPolicy: cdk.RemovalPolicy.RETAINに変更
監視項目一覧
| 監視区分 | 監視項目 | 閾値 | 説明 |
|---|---|---|---|
| 死活監視 | システムステータスチェック | 失敗検知 | AWS基盤レベルの問題検出 |
| 死活監視 | インスタンスステータスチェック | 失敗検知 | インスタンスレベルの問題検出 |
| リソース監視 | CPU使用率 | 90%以上 | プロセッサーの負荷監視 |
| リソース監視 | メモリ使用率 | 90%以上 | メモリリソースの使用量監視 |
| リソース監視 | ディスク使用率(C:) | 10%未満 | システムドライブの空き容量 |
| リソース監視 | ディスク使用率(D:) | 10%未満 | データドライブの空き容量 |
| プロセス監視 | svchost.exe | 1以下 | 重要システムプロセスの監視 |
| イベントログ監視 | システムログ | エラー検出 | システムレベルのエラー監視 |
| イベントログ監視 | アプリケーションログ | エラー検出 | アプリケーションエラー監視 |
| イベントログ監視 | セキュリティログ | エラー検出 | セキュリティ関連エラー監視 |
今回実装したコンストラクトファイルまとめ
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as subscriptions from 'aws-cdk-lib/aws-sns-subscriptions';
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
import * as actions from 'aws-cdk-lib/aws-cloudwatch-actions';
import * as logs from 'aws-cdk-lib/aws-logs';
export interface EC2WinMonitoringConstructProps {
// 必要に応じて追加のプロパティを定義
}
export class EC2WinMonitoringConstruct extends Construct {
constructor(scope: Construct, id: string, props?: EC2WinMonitoringConstructProps) {
super(scope, id);
//===========================================
// EC2インスタンス
//===========================================
const ec2Instance = 'i-xxxxxxxxxxxxxxxxx' // 監視対象のインスタンスIDを指定
//===========================================
// SNS
//===========================================
const emailAddresses = [ // SNS通知先メーリングリスト(通知先が複数ある場合アドレスを追加)
'xxxxxx@example.com',
'xxxxxxx@example.com',
];
// CloudWatchアラーム用トピック
const alarmTopic = new sns.Topic(this, 'AlarmTopic', {
topicName: 'clw-alertnotification', // トピック名
displayName: 'Cloudwatch Alert Notifications' // 表示名
});
// CloudWatchアラーム用サブスクリプション
emailAddresses.forEach(email => {
alarmTopic.addSubscription(
new subscriptions.EmailSubscription(email) // プロトコル:EMAIL
);
});
//===========================================
// CloudWatchアラーム
//===========================================
// システム死活監視
const statusCheckFailedSystemAlarm = new cloudwatch.Alarm(this, 'StatusCheckFailedSystemAlarm', {
alarmName: 'alarm-ec2-scfs',
metric: new cloudwatch.Metric({
namespace: 'AWS/EC2',
metricName: 'StatusCheckFailed_System', // メトリクス名
dimensionsMap: {
InstanceId: ec2Instance,
},
statistic: 'sum', // 統計:合計
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値(1以上=失敗あり)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
statusCheckFailedSystemAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
statusCheckFailedSystemAlarm.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
// インスタンス死活監視
const statusCheckFailedInstanceAlarm = new cloudwatch.Alarm(this, 'StatusCheckFailedInstanceAlarm', {
alarmName: 'alarm-ec2-scfi',
metric: new cloudwatch.Metric({
namespace: 'AWS/EC2',
metricName: 'StatusCheckFailed_Instance', // メトリクス名
dimensionsMap: {
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID
},
statistic: 'sum', // 統計:合計
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値(1以上=失敗あり)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
statusCheckFailedInstanceAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
statusCheckFailedInstanceAlarm.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
// CPU使用率アラーム
const cpuAlarm = new cloudwatch.Alarm(this, 'CpuAlarm', {
alarmName: 'alarm-ec2-cpu',
metric: new cloudwatch.Metric({
namespace: 'AWS/EC2',
metricName: 'CPUUtilization', // メトリクス名
dimensionsMap: {
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID
},
statistic: 'Average', // 統計:平均
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 90, // アラームの閾値(CPU使用率90%)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
cpuAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
cpuAlarm.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
// メモリ使用率アラーム
const memoryAlarm = new cloudwatch.Alarm(this, 'MemoryAlarm', {
alarmName: 'alarm-ec2-mem',
metric: new cloudwatch.Metric({
namespace: 'CWAgent',
metricName: 'Memory % Committed Bytes In Use', // メトリクス名
dimensionsMap: { // 取得に必要な変数
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID(config.jsonのappend_dimensionsで指定)
objectname: 'Memory' // オブジェクト名(config.jsonのmetrics_collectedで指定)
},
statistic: 'Average', // 統計:平均
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 90, // アラームの閾値(メモリ使用率90%)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
memoryAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
memoryAlarm.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
// ディスク使用率アラーム
const diskAlarmC = new cloudwatch.Alarm(this, 'DiskAlarmC', {
alarmName: 'alarm-ec2-dsk-c',
metric: new cloudwatch.Metric({
namespace: 'CWAgent',
metricName: 'LogicalDisk % Free Space', // メトリクス名
dimensionsMap: {
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID(config.json側のappend_dimensionsで指定)
instance: 'C:', // 対象ディスク
objectname: 'LogicalDisk' // オブジェクト名(config.json側のmetrics_collectedで指定)
},
statistic: 'Average', // 統計:平均
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 10, // アラームの閾値
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD, // アラーム条件: より小さい
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
diskAlarmC.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
diskAlarmC.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
const diskAlarmD = new cloudwatch.Alarm(this, 'diskDAlarmD', {
alarmName: 'alarm-ec2-dsk-d',
metric: new cloudwatch.Metric({
namespace: 'CWAgent',
metricName: 'LogicalDisk % Free Space', // メトリクス名
dimensionsMap: {
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID(config.json側のappend_dimensionsで指定)
instance: 'D:', // 対象ディスク
objectname: 'LogicalDisk' // オブジェクト名(config.json側のmetrics_collectedで指定)
},
statistic: 'Average', // 統計:平均
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 10, // アラームの閾値
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD, // アラーム条件: より小さい
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
diskAlarmD.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
diskAlarmD.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
// プロセス監視アラーム
const svchostServiceAlarm = new cloudwatch.Alarm(this, 'SVCHostServiceAlarm', {
alarmName: 'alarm-svchost',
metric: new cloudwatch.Metric({
namespace: 'CWAgent',
metricName: 'procstat_lookup pid_count', // メトリクス名(プロセスに関連付けられたプロセスIDの数)
dimensionsMap: {
InstanceId: ec2Instance, // 監視対象のEC2インスタンスID(config.json側のappend_dimensionsで指定)
exe: 'svchost.exe', // 監視対象のプロセス名
pid_finder: 'native' // プロセスの検出方法:native(OSのネイティブAPIを使用)
},
statistic: 'Min', // 統計: 最小
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.LESS_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件:閾値以下
treatMissingData:
cloudwatch.TreatMissingData.BREACHING, // 欠落データを不正(しきい値を超えている)として処理
});
svchostServiceAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
svchostServiceAlarm.addOkAction(new actions.SnsAction(alarmTopic)); // アラームがOK状態に戻った時のSNS通知先
// イベントログ(システムログ)用のロググループのエラー監視アラーム
const sytemLogErrorsAlarm = new cloudwatch.Alarm(this, 'SystemLogErrorsAlarm', {
alarmName: 'os-eventlog-system',
metric: new cloudwatch.Metric({
namespace: 'os-cloudwatchlogs', // カスタムメトリクスの名前空間(CloudwachLogsで作成した名前空間を指定)
metricName: 'OS-Eventlog-System', // メトリクス名
statistic: 'Sum', // 統計:合計
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値(1以上=失敗あり)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
sytemLogErrorsAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
// イベントログ(アプリケーションログ)用のロググループのエラー監視アラーム
const appLogErrorsAlarm = new cloudwatch.Alarm(this, 'ApplicationLogErrorsAlarm', {
alarmName: 'os-eventlog-application',
metric: new cloudwatch.Metric({
namespace: 'os-cloudwatchlogs', // カスタムメトリクスの名前空間(CloudwachLogsで作成した名前空間を指定)
metricName: 'OS-Eventlog-Application', // メトリクス名
statistic: 'Sum', // 統計:合計
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値(1以上=失敗あり)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
appLogErrorsAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
// イベントログ(セキュリティログ)用のロググループのエラー監視アラーム
const securityLogErrorsAlarm = new cloudwatch.Alarm(this, 'SecurityLogErrorsAlarm', {
alarmName: 'os-eventlog-security',
metric: new cloudwatch.Metric({
namespace: 'os-cloudwatchlogs', // カスタムメトリクスの名前空間(CloudwachLogsで作成した名前空間を指定)
metricName: 'OS-Eventlog-Security', // メトリクス名
statistic: 'Sum', // 統計:合計
period: cdk.Duration.minutes(5), // メトリクスの収集間隔(期間):5分
}),
threshold: 1, // アラームの閾値(1以上=失敗あり)
evaluationPeriods: 1,
datapointsToAlarm: 1,
comparisonOperator:
cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, // アラーム条件: 閾値以上
treatMissingData:
cloudwatch.TreatMissingData.MISSING, // 欠落データを見つかりませんとして処理
});
securityLogErrorsAlarm.addAlarmAction(new actions.SnsAction(alarmTopic)); // アラーム発生時のSNS通知先
//================================================
// CloudWatchLogs作成
//================================================
// OSイベントログ(システムログ)用のロググループ
const systemLogGroup = new logs.LogGroup(this, 'SystemLogGroup', {
logGroupName: 'loggroup-os-eventlog-system',
retention: logs.RetentionDays.ONE_MONTH, // 保持期間: 1ヵ月
removalPolicy: cdk.RemovalPolicy.DESTROY
});
const systemErrorMetricFilter = new logs.MetricFilter(this, 'SystemErrorMetricFilter', { // イベントログ(システムログ)用メトリクスフィルター
logGroup: systemLogGroup,
filterName: 'filter-os-eventlog-system', // フィルター名
filterPattern: logs.FilterPattern.literal('?ERROR ?Error ?error ?FAIL ?Fail ?fail'), // フィルターパターン
metricNamespace: 'os-cloudwatchlogs', // メトリクス名前空間
metricName: 'OS-Eventlog-System', // メトリクス名
metricValue: '1', // メトリクス値
defaultValue: 0
});
// OSイベントログ(アプリケーションログ)用のロググループ
const applicationLogGroup = new logs.LogGroup(this, 'ApplicationLogGroup', {
logGroupName: 'loggroup-os-eventlog-application',
retention: logs.RetentionDays.ONE_MONTH, // 保持期間: 1ヵ月
removalPolicy: cdk.RemovalPolicy.DESTROY
});
const applicationErrorMetricFilter = new logs.MetricFilter(this, 'ApplicationErrorMetricFilter', { // イベントログ(アプリケーションログ)用メトリクスフィルター
logGroup: applicationLogGroup,
filterName: 'filter-os-eventlog-application', // フィルター名
filterPattern: logs.FilterPattern.literal('?ERROR ?Error ?error ?FAIL ?Fail ?fail'), // フィルターパターン
metricNamespace: 'os-cloudwatchlogs', // メトリクス名前空間
metricName: 'OS-Eventlog-Application', // メトリクス名
metricValue: '1', // メトリクス値
defaultValue: 0
});
// OSイベントログ(セキュリティログ)用のロググループ
const securityLogGroup = new logs.LogGroup(this, 'SecurityLogGroup', {
logGroupName: 'loggroup-os-eventlog-security',
retention: logs.RetentionDays.ONE_MONTH, // 保持期間: 1ヵ月
removalPolicy: cdk.RemovalPolicy.DESTROY
});
const securityErrorMetricFilter = new logs.MetricFilter(this, 'SecurityErrorMetricFilter', { // イベントログ(セキュリティログ)用メトリクスフィルター
logGroup: securityLogGroup,
filterName: 'filter-os-eventlog-security', // フィルター名
filterPattern: logs.FilterPattern.literal('?ERROR ?Error ?error ?FAIL ?Fail ?fail'), // フィルターパターン
metricNamespace: 'os-cloudwatchlogs', // メトリクス名前空間
metricName: 'OS-Eventlog-Security', // メトリクス名
metricValue: '1', // メトリクス値
defaultValue: 0
});
}
}
Cloud Watch Agent Jsonサンプル
{
"agent": {
"metrics_collection_interval": 60,
"run_as_user": "System"
},
"logs": {
"logs_collected": {
"windows_events": {
"collect_list": [
{
"event_name": "System",
"event_levels": [
"ERROR",
"WARNING",
"INFORMATION"
],
"log_group_name": "loggroup-os-eventlog-system",
"log_stream_name": "{local_hostname}_{instance_id}"
},
{
"event_name": "Application",
"event_levels": [
"ERROR",
"WARNING",
"INFORMATION"
],
"log_group_name": "loggroup-os-eventlog-application",
"log_stream_name": "{local_hostname}_{instance_id}"
},
{
"event_name": "Security",
"event_levels": [
"ERROR",
"WARNING",
"INFORMATION",
"CRITICAL"
],
"log_group_name": "loggroup-os-eventlog-security",
"log_stream_name": "{local_hostname}_{instance_id}"
}
]
}
}
},
"metrics": {
"namespace": "CWAgent",
"metrics_collected": {
"Memory": {
"measurement": [
"% Committed Bytes In Use"
],
"metrics_collection_interval": 60
},
"LogicalDisk": {
"measurement": [
"% Free Space"
],
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"Processor": {
"measurement": [
"% Processor Time"
],
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"procstat": [
{
"exe": "svchost.exe",
"measurement": [
"pid_count"
],
"metrics_collection_interval": 60
}
]
},
"append_dimensions": {
"InstanceId": "${aws:InstanceId}"
}
}
}
まとめ
今回は、Windows EC2インスタンスの包括的な監視システムをAWS CDKで実装しました。
本実装ではリソースはマネジメントコンソールで作成する場合でも監視をAWS CDKを用いて構築することが出来ます。
IaCとして管理することで、環境間での一貫した監視設定の展開や、監視ルールの変更履歴管理も可能になります。また、CloudWatch Agent設定ファイルと組み合わせることで、Windows固有のメトリクスやログを効率的に収集・監視できます。
皆さんのお役に立てれば幸いです。

