AWS CDK で Amazon EC2 監視機能を実装してみた

今回は、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固有のメトリクスやログを効率的に収集・監視できます。

皆さんのお役に立てれば幸いです。

タイトルとURLをコピーしました