Amazon CloudWatchでWindowsのプロセス監視をしてみた

しばたです。

Amazon CloudWatch(以後CloudWatch)で各種メトリクスを収集するためのCloudWatch Agentにはprocstatプラグインと呼ばれる機能があり、特定のプロセスに対する様々なメトリクスを収集することができます。

こちらの機能については弊社園部の以下の記事に詳しく記載されています。

CloudWatch Agent でProcstatプラグインの利用が可能になりました

procstatプラグインの機能を応用すると特定のプロセスに対する死活監視を行うことが可能です。
たとえば以下の記事では起動しているhttpdプロセスの数をメトリクスに記録し、プロセス数が0になった場合(=プロセスが死んだ場合)にCloudWatch Alermのアクションでプロセスを再起動するといったことをしています。

ただ、AWS公式ドキュメントも上記2つのブログ記事もLinuxサーバーを対象とした内容でWindowsサーバーを対象にした設定例を見つけることができませんでした。

そこで本記事ではWindows Serverに対してprocstatプラグインを使いプロセス監視を行ってみます。

検証環境

今回はインターネットへアクセス可能なWindows Server 2019のEC2インスタンスを1台用意し、Systems Manager Run Commandを使って最新のCloudWatch Agentをインストールします。

EC2インスタンスにアタッチするIAMロールは以下。

  • AmazonSSMManagedInstanceCore : SSM用
  • CloudWatchAgentServerPolicy : CloudWatch Agent用

2つのポリシーを与えています。

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  RoleName:
    Description: "Input SSM role name."
    Type: String
    Default: "EC2RoleforSSMAndCloudWatch"
Resources:
  # IAM Role
  SSMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName:
        Fn::Sub: "${RoleName}"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
        - "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
  # Instance Profile
  SSMRoleInstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      InstanceProfileName:
        Fn::Sub: "${RoleName}"
      Path: "/"
      Roles:
        - Ref: SSMRole

このIAMロールをアタッチしたEC2インスタンスに対し以下の様な感じでAWS-ConfigureAWSPackageを実行してCloudWatch Agentをインストールします。
(今回はAWS Tools for PowerShellで設定してみました)

# 既定のリージョンおよびプロファイルの指定は環境に合わせて行ってください
Set-DefaultAWSRegion -Region ap-northeast-1
Set-AWSCredential -ProfileName your-profile

# CloudWatch Agentのインストール
$params = @{
    InstanceId = 'i-01234567890'; # EC2インスタンスのインスタンスID
    DocumentName = 'AWS-ConfigureAWSPackage';
    Parameter = @{
        action = 'Install';
        name = 'AmazonCloudWatchAgent';
    };
}
Send-SSMCommand @params

# 戻り値の処理はよしなに行ってください

これでCloudWatch Agentをインストールした状態のEC2インスタンスが準備できました。

Amazon CloudWatchでWindowsのプロセス監視をしてみた

ここからプロセス監視の設定を実際に試していきます。

procstatプラグインでは3つの方法でメトリクスを収集するプロセスを指定することができます。

  • pid_file: 作成するプロセス識別番号 (PID) ファイルの名前でプロセスを選択します。
  • exe: 正規表現の照合ルールを使用して、指定した文字列と一致するプロセス名のプロセスを選択します。詳細については、「Syntax」を参照してください。
  • pattern: プロセスの起動に使用するコマンドラインでプロセスを選択します。正規表現の照合ルールを使用して指定した文字列と一致するコマンドラインを持つすべてのプロセスが選択されます。コマンドで使用されるパラメータやオプションも含めて、コマンドライン全体がチェックされます。

以降3つの方法を順に試していきます。

1. PIDファイルの監視

起動したプロセスのIDをファイルに書き出し監視などに使う、いわゆるPIDファイルから指定のプロセスに対するメトリクスを取得する方法です。

Linuxなどでは良くある方式ですがWindowsではPIDファイルを作るのは一般的ではありません。
良い例を思いつかなかったので今回はPowerShellコンソールを起動し、そのプロセスIDを適当なファイルに書き出し監視してみます。

# PowerShellコンソールのプロセスIDを適当なファイルに書き出す
mkdir C:\temp
$PID | Out-File C:\temp\powershell.pid -Encoding ascii

これで疑似PIDファイルはできました。

次に以下のJSONファイルをSSMパラメーターストアに保存します。
この設定ではpid_fileで指定されたファイルを監視し、そのプロセスのプロセス数(pid_count)をメトリクスとして記録します。
基本的にはプロセスが起動していれば1となり、プロセスが終了していれば0となります。
ファイルパスについてJSONでは\をエスケープする必要があるので\\区切りとしています。

{
    "metrics": {
        "metrics_collected": {
            "procstat": [
                {
                    "pid_file": "C:\\temp\\powershell.pid",
                    "measurement": [
                        "pid_count"
                    ],
                    "metrics_collection_interval": 60
                }
            ]
        }
    }
}

また、パラメーター名はAmazonCloudWatch-で始まる必要があるのでAmazonCloudWatch-windows-sampleとしておきます。

このパラメーターを該当インスタンスのCloudWatch Agentに反映させます。
AmazonCloudWatch-ManageAgentドキュメントを以下の様な引数で実行します。

# 既定のリージョンおよびプロファイルの指定は環境に合わせて行ってください
Set-DefaultAWSRegion -Region ap-northeast-1
Set-AWSCredential -ProfileName your-profile

# CloudWatch Agentのインストール
$params = @{
    InstanceId = 'i-01234567890'; # EC2インスタンスのインスタンスID
    DocumentName = 'AmazonCloudWatch-ManageAgent';
    Parameter = @{
        action = 'configure';
        mode = 'ec2';
        optionalConfigurationSource = 'ssm';
        optionalConfigurationLocation= 'AmazonCloudWatch-windows-sample';
        optionalRestart = 'yes'
    };
}
Send-SSMCommand @params

# 戻り値の処理はよしなに行ってください

設定がうまく反映されると下図の様にCloudWatchのCWAgent名前空間にhost, pid_finder, pidfileという名前のメトリクスが記録されます。

メトリクスを確認すると該当インスタンスの指定プロセス情報が収集されます。

(この図だと1点だけ0.6という半端な値が記録されているのですが理由については正直わかりません...)

2. プロセス名の監視

続けてプロセス名を指定した監視を試してみます。

以下のJSONファイルをSSMパラメーターストアに保存します。
今度はexeセクションに監視したいプロセス名を記載します。
今回はCloudWatch Agentサービスの実体であるstart-amazon-cloudwatch-agent.exeを設定しています。その他のパラメーターについてはPIDファイルの監視と同様です。

{
    "metrics": {
        "metrics_collected": {
            "procstat": [
                {
                    "exe": "start-amazon-cloudwatch-agent.exe",
                    "measurement": [
                        "pid_count"
                    ],
                    "metrics_collection_interval": 60
                }
            ]
        }
    }
}

この設定をPIDファイルの時と同様の手順でEC2インスタンスのCloudWatch Agentに反映させます。
設定がうまく反映されると下図の様にCloudWatchのCWAgent名前空間にexe, host, pid_finderという名前のメトリクスが記録されます。

3. コマンドラインの監視

最後にコマンドラインの監視を試します。

以下のJSONファイルをSSMパラメーターストアに保存します。
patternセクションに監視したいプロセスのコマンドラインを記載します。
今回はGroup Policy Clientサービスの実体であるC:\Windows\system32\svchost.exe -k netsvcs -p -s gpsvcを設定しています。その他のパラメーターについてはPIDファイルの監視と同様です。

{
    "metrics": {
        "metrics_collected": {
            "procstat": [
                {
                    "pattern": "C:\\Windows\\system32\\svchost.exe -k netsvcs -p -s gpsvc",
                    "measurement": [
                        "pid_count"
                    ],
                    "metrics_collection_interval": 60
                }
            ]
        }
    }
}

svchostはいくつかのネットワーク系サービスで共用されるプログラムで引数の違いで対象となるサービスが変わるので前項のexeセクションでは設定することができません。
patternセクションで引数まで指定してやることで個々のサービスを特定してやることができます。

この設定をこれまでと同様の手順でEC2インスタンスのCloudWatch Agentに反映させます。
設定がうまく反映されると下図の様にCloudWatchのCWAgent名前空間にhost, pattern, pid_finderという名前のメトリクスが記録されます。

【補足】プロセス検索の実装について

補足としてexepatternセクションの仕様について触れておきます。
これらのセクションでプロセス名およびコマンドラインを検索する際の仕様は先述のドキュメントでは以下の通り記載されています。

Linux サーバーの場合、exe セクションまたは pattern セクションで指定した文字列は正規表現として評価されます。
Windows Server を実行するサーバーの場合、これらの文字列は WMI クエリとして評価されます。詳細については、「LIKE Operator」を参照してください。

大事なことはWindowsの場合はWMIクエリの仕様に基づいてプロセスが検索されるという点です。

CloudWatch Agentはソースが公開されていないため確認がとれず、私の推測を含むのですが、procstatプラグインは指定されたプロセスを検索する際にWMIのWin32_Processクラスを使っているのでしょう。
そしてWQLのLike演算子がリンクされていることから、内部的には、

# exeセクションの予想WQL
SELECT * FROM Win32_Process WHERE Name LIKE '<JSON指定のパターン>';

# patternセクションの予想WQL
SELECT * FROM Win32_Process WHERE CommandLine LIKE '<JSON指定のパターン>';

といったWQLを発行していると予想されます。
該当プロセスを検索する際のパターンを考慮するときはこのWQLを意識すると期待した動作をさせることが出来ると思います。