今回は、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固有のメトリクスやログを効率的に収集・監視できます。 皆さんのお役に立てれば幸いです。