AWS Tools for PowerShellを使いCloudWatchカスタムメトリクスを作成する

しばたです。

様々な事情によりアプリケーションから独自のCloudWatchカスタムメトリクスを作成してメトリクスを記録したいことは多いかと思います。
本記事ではAWS Tools for PowerShellを使いPowerShellでカスタムメトリクスを作成する方法を紹介します。

公式ドキュメント

AWS Tools for PowerShellを使いPowerShellでカスタムメトリクスを作成する手順は以下のユーザーガイドに記載されています。

このユーザーガイドは必要最低限の内容となっており、AWS Tools for PowerShellに慣れた方にとっては十分かもしれませんが、慣れていない方にとっては若干情報不足だと思われます。
本記事ではこのユーザーガイドをもう少し補足する形で解説します。

AWS Tools for PowerShellを使いCloudWatchカスタムメトリクスを作成する

ここから本題に入ります。

前提条件

本記事の内容を実行するための前提条件は以下となります。

  • AWS Tools for PowerShellがインストールされていること
  • カスタムメトリクスを発行するのに適切な権限(cloudwatch:PutMetricData)があること

今回はテスト用に適当なWindows Server 2016 EC2インスタンスを想定環境とします。
EC2インスタンスに適切な権限を持ったIAMロールが割り当てられている前提です。

Write-CWMetricData

AWS Tools for PowerShellを使いPowerShellでカスタムメトリクスのデータを発行するにはWrite-CWMetricDataコマンドレットを使います。

このコマンドレットのパラメーター自体は割と単純で、メトリクスの名前空間を指定する-Namespaceパラメーターと、メトリクスデータである-MetricDataパラメーターを指定するだけで利用できます。

Write-CWMetricData -Namespace <String> -MetricData <MetricDatum[]>

ちょっと厄介なのが-MetricDataパラメーターで、このパラメーターはAmazon.CloudWatch.Model.MetricDatum型の配列を指定します。
.NET SDK生のオブジェクトをそのまま引き渡す形となっており、PowerShellらしさに若干欠けます。
New-ObjectコマンドレットでMetricDatum型のオブジェクトを生成し必要なプロパティを設定、Write-CWMetricDataに指定する形となります。

以下でユーザーガイドにある例を解説します。

# メトリクス情報は Amazon.CloudWatch.Model.MetricDatum 型のオブジェクトを生成する必要がある
$dat = New-Object Amazon.CloudWatch.Model.MetricDatum
$dat.Timestamp = (Get-Date).ToUniversalTime() # メトリクスのタイムスタンプはUTCで指定
$dat.MetricName = "New Posts" # メトリクス名
$dat.Unit = "Count" # メトリクスの単位
$dat.Value = ".50"  # メトリクスの値
# Write-CWMetricData の -MetricData パラメーターに引き渡す
Write-CWMetricData -Namespace "Usage Metrics" -MetricData $dat

加えてユーザーガイドに記載されていない大事な部分としてメトリクスのディメンションはSystem.Collections.Generic.List<Amazon.CloudWatch.Model.Dimension>型のDimensionsプロパティで指定します。

# メトリクス情報は Amazon.CloudWatch.Model.MetricDatum 型のオブジェクトを生成する必要がある
$dat = New-Object Amazon.CloudWatch.Model.MetricDatum
# ディメンションは Dimensions プロパティで設定する
$d1 = New-Object Amazon.CloudWatch.Model.Dimension
$d1.Name = "InstanceId"
$d1.Value = "i-0123456789abc"
$d2 = New-Object Amazon.CloudWatch.Model.Dimension
$d2.Name = "DriveName"
$d2.Value = "C:"
$dat.Dimensions = @($d1, $d2) 

PowerShellで扱う場合はAmazon.CloudWatch.Model.Dimension型の配列で渡してやればよしなに型変換してくれるのですが、非常に"らしくない"感じで残念です。

その他MetricDatum型オブジェクトで指定可能なプロパティの詳細は.NET SDKのドキュメントを参照してください。

実装サンプル

最後にもう少し実践的な例を提示して終わりにします。

EC2インスタンス内のWindowsサービス(今回はSSM Agentサービス)の状態を取得し、サービスが起動していれば1、そうでない状態であれば0を記録するメトリクスを作成してみます。
CloudWatch Alermと組み合わせれば簡易的にWindowsサービス監視をすることができるメトリクスです。

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

# ディメンションの扱いが"らしくない"ので簡単なヘルパー関数を作成
# HashTableの各値をDimensionオブジェクトに変換します
function ConvertTo-Dimension ([HashTable]$Hash) {
    foreach ($key in $Hash.Keys) {
        $dim = New-Object Amazon.CloudWatch.Model.Dimension
        $dim.Name = $key
        $dim.Value = $Hash[$key]
        Write-Output $dim
    }
}

# SSM Agent サービスの状態を取得
$service = Get-Service AmazonSSMAgent

$params = @{
    Namespace = "My Windows Service Monitoring";
    MetricData = &{
        # ディメンションはインスタンスIDとサービス名
        $dimensions = @{
            InstanceId = Get-EC2InstanceMetadata -Category InstanceId;
            ServiceName = $service.Name
        }
        $dat = New-Object Amazon.CloudWatch.Model.MetricDatum
        $dat.Dimensions = (ConvertTo-Dimension $dimensions)
        $dat.Timestamp = (Get-Date).ToUniversalTime()
        $dat.MetricName = $service.DisplayName
        $dat.Unit = 'None'
        # サービスが起動していれば1、その他の状態であれば0
        $dat.Value = if ($service.Status -eq 'Running') { 1 } else { 0 }
        return $dat 
    };
}
Write-CWMetricData @params

このスクリプトを実行するとこんな感じでカスタムメトリクスが記録されます。

(今回はPowerShellコンソール上で実行していますが、実際の運用ではスクリプト化したほうが良いでしょう)

結果CloudWatchメトリクスに「My Windows Service Monitoring」名前空間が増えており、良い感じにメトリクスが記録されています。
あとはWindowsタスクスケジューラーなど様々な方法で定期実行してやればメトリクスを継続して記録できる様になります。

以上となります。
ユーザーガイドで若干不足している部分を補完し、簡単ではあるものの、単体で実行可能なスクリプトにしてますので参考にしてみてください。