Windows 用 CloudWatch エージェントのバージョンを一括で取得したい
コンバンハ、千葉(幸)です。
とある事情から、環境に存在する Windows EC2 インスタンスにインストールされた CloudWatch エージェントのバージョンを確認したい機会がありました。
具体的には、v1.247354
以前のバージョンを使用しているインスタンスがないかを確認したいです。環境に存在するインスタンスが数十台あるので、個別に1台ずつログオンして確認するようなことはしたくありません。
Systems Manager の機能を用いていい感じにできないか検討しました。
まとめ
- Systems Manager インベントリの機能を有効化しているとインスタンスにインストールされたアプリケーションのバージョンを確認できる
- インベントリで確認できる Windows の CloudWatch エージェントのバージョンは正しいものではない
- 作り込みせずにバージョンを取得したいのであれば Systems Manager Run Command が便利
話の前提
今回はインスタンスが Systems Manager の管理ノードになっていることを前提としています。言い換えれば、Systems Manager コンソールの「フリートマネージャー」→「マネージドノード」に表示されている状態であることを前提としています。
管理ノードになるためには、Systems Manager エージェント、インスタンスプロファイル(IAMロール)、ネットワーク経路など、いくつか条件を満たしている必要があります。詳細は以下をご参照ください。
aws ssm list-inventory-entries で取得してみたが何やらおかしい
今回わたしが試行した環境では各マネージドノードで Systems Manager インベントリが有効になっていました。
aws ssm list-inventory-entries
コマンドを使用すればインベントリに収集された情報を取得できます。
以下のように指定してあげれば CloudWatch エージェントのバージョンを取得できそうです。
aws ssm list-inventory-entries\ --instance-id xxxx\ --type-name AWS:Application\ --filters Key=Name,Values="Amazon CloudWatch Agent",Type=Equal
以下のようにaws ec2 describe-instances
と組み合わせてループ処理を実行し、各インスタンスにおけるバージョンが取得できました。めでたしめでたし……と考えていました。
% echo "InstanceId Version" > /tmp/awscli.tmp aws ec2 describe-instances --query "Reservations[].Instances[].[InstanceId]" --output text | while read line;\ do echo ${line} > /tmp/awscli-instance.tmp;\ aws ssm list-inventory-entries --instance-id ${line} --type-name AWS:Application --filters Key=Name,Values="Amazon CloudWatch Agent",Type=Equal --query "Entries[].Version" --output text >> /tmp/awscli-instance.tmp;\ cat /tmp/awscli-instance.tmp | tr "\n" " " | sed 's/$/\n/g' >> /tmp/awscli.tmp;\ done column -t /tmp/awscli.tmp;\ rm /tmp/awscli.tmp /tmp/awscli-instance.tmp InstanceId Version i-0c6f3xxxxxxxxxxxx i-09c4cxxxxxxxxxxxx 1.3.50739 i-0036exxxxxxxxxxxx i-052e6xxxxxxxxxxxx 1.3.50739 i-0e297xxxxxxxxxxxx 1.3.50739 i-01ab9xxxxxxxxxxxx 1.3.50739 ...
取得できたバージョンをよくよく見ると何かが違います。今回は「v1.247354
以前のものかどうか」を確認したかったですが、1.3
の後にピリオドが入っているあたりバージョンの構成が違いそうです。
念のため CloudWatch エージェントのリリースノートを見てみますが、1.3.
から始まるバージョンは存在しません。
正しいバージョンを取得したいときはコマンド実行が必要
以下エントリに答えがありました。
AWS ドキュメントによると Windows サーバー上の CloudWatch エージェントのバージョン番号を確認するには次のコマンドを実行する必要あり、とされています。
& $Env:ProgramFiles\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1 -m ec2 -a status
注記
このコマンドを使用することは、CloudWatch エージェントのバージョンを検索する正しい方法です。コントロールパネルの [Programs and Features (プログラムと機能)] を使用すると、誤ったバージョン番号が表示されます。
「誤ったバージョン番号が表示されます。」そんな……。
Run Command で複数台に同時にコマンドを実行する
先述のエントリでは Windows サーバー上の CloudWatch エージェントのバージョン番号を確認するコマンドを載せてくれています。
function Get-CloudWatchAgentVersion () { $agentCtlPath = "$env:ProgramFiles\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1" if (-not (Test-Path -LiteralPath $agentCtlPath)) { return "Not installed" } return (& $agentCtlPath -m ec2 -a status ) | ConvertFrom-Json | Select-Object -ExpandProperty version } Get-CloudWatchAgentVersion
これを Systems Manager Run Command で実行してあげれば、ある程度ラクにバージョン番号が取得できます。早速やってみます。
「AWS Systems Manager」→「 Run Command」→「コマンドの実行」と進みます。
コマンドドキュメントにAWS-RunPowerShellScript
を選択し、バージョンはデフォルトを指定します。
パラメータCommands
に先ほどのコマンドの内容を入力します。その他のパラメータはデフォルトのままにします。
ターゲットを指定します。例えばタグによって適切にグルーピングできているようであればタグ指定するのも良いでしょう。
今回は個別にインスタンスを指定していきます。プラットフォームがここで確認できるので「Windowsのインスタンスのみ対象にする」ということも楽です。
その他以下を必要に応じて指定し、コマンドを実行します。
- コメント(メモ)
- タイムアウト秒数
- レート制御
- 同時実行数
- エラーのしきい値
- ログ出力
- S3 バケット
- CloudWatch Logs
- CloudWatch アラーム(対象のインスタンスに関するアラームが上がったら中止)
- SNS 通知(コマンド実行ステータスの通知)
↑ わたしは特に上記を指定/変更せずコマンド実行しました。
20 台を対象に実行し、ほんの数秒で完了しました。
ターゲットごとに出力を確認すると、このようにバージョン情報が取得できています。
この出力を1台ずつ確認していくのが手間といえば手間なのですが、許容できる範囲かなということで今回はこの方式で賄いました。
ここで取得した情報を一箇所に集約して一覧表示、みたいなこともできる予感もするので、もっとスマートなやり方が思いつく方は教えていただけると嬉しいです。
2022/12/30追記
こんな感じで AWS CLI で一括取得できました。
$ COMMAND_ID=xxxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxxxxxx $ aws ssm list-command-invocations --command-id $COMMAND_ID --details\ --query "sort_by(CommandInvocations, &InstanceId)[].[InstanceId, InstanceName, Status, CommandPlugins[0].Output]" \ --output text | awk 'BEGIN {print "InstanceId, InstanceName, Status, Output"} { print $1", "$2", "$3", "$4 }' | column -t -s ',' | sed '/^ *$/d' InstanceId InstanceName Status Output i-0xxxxxxxxxxxxxxxx HOSTNAME-A Success 1.247349.0b251399 i-0xxxxxxxxxxxxxxxx HOSTNAME-B Success 1.247348.0b251302 i-0xxxxxxxxxxxxxxxx HOSTNAME-C Success 1.247347.4b250525 i-0xxxxxxxxxxxxxxxx HOSTNAME-D Success 1.247347.6b250880 i-0xxxxxxxxxxxxxxxx HOSTNAME-E Success 1.247349.0b251399 i-0xxxxxxxxxxxxxxxx HOSTNAME-F Success 1.231221.0 ...
終わりに
Windows 用 CloudWatch エージェントのバージョンを一括で取得したい、という内容でした。
Systems Manager インベントリで取得できるバージョンが正しいものではないというのが完全に想定外でしたが、ある程度楽に取得できる手法が見つかってよかったです。
今回は単発の実施だったため採用しませんでしたが、定期的に取得したいという場合には以下エントリのようにカスタムインベントリの採用をご検討ください。
CloudWatch エージェントでは少し罠がありましたが、Systems Manager インベントリを使用することで「各インスタンスにインストールされたアプリケーションのバージョンを一括取得できる」ということを覚えておくと役に立つかもしれません。
参考になれば幸いです。
以上、 チバユキ (@batchicchi) がお送りしました。
余談:aws ssm describe-instance-information
今回は結果的に空振りに終わったのですが、以下のように「インスタンス一覧を取得してそれぞれにループ処理でインベントリ情報取得」を試行した、というのは先述の通りです。
echo "InstanceId Version" > /tmp/awscli.tmp aws ec2 describe-instances --query "Reservations[].Instances[].[InstanceId]" --output text | while read line;\ do echo ${line} > /tmp/awscli-instance.tmp;\ aws ssm list-inventory-entries --instance-id ${line} --type-name AWS:Application --filters Key=Name,Values="Amazon CloudWatch Agent",Type=Equal --query "Entries[].Version" --output text >> /tmp/awscli-instance.tmp;\ cat /tmp/awscli-instance.tmp | tr "\n" " " | sed 's/$/\n/g' >> /tmp/awscli.tmp;\ done column -t /tmp/awscli.tmp;\ rm /tmp/awscli.tmp /tmp/awscli-instance.tmp
ここでは「インスタンス一覧の取得」にaws ec2 describe-instances
を使用したのですが、他にもaws ssm describe-instance-information
コマンドも候補になります。
こちらのコマンドではプラットフォーム情報も取得できたりと嬉しい部分があります。先ほど引用したエントリでは以下のようなオシャレなコマンドの使い方をしています。
aws ssm describe-instance-information \ --query "sort_by(InstanceInformationList, &ComputerName)[].[InstanceId, PlatformType]" \ --output text | awk 'BEGIN {print "InstanceId, Platform, Version"} { "aws ssm list-inventory-entries --instance-id "$1" --type-name \"AWS:Application\" --filters \"Key=Name,Values=Amazon CloudWatch Agent, amazon-cloudwatch-agent\" --query \"Entries[0].Version\" --output text" | getline version print $1", "$2", "version }' | column -t -s ','
ただ、aws ssm describe-instance-information
で取得できる対象は以下のみのようでした。
- マネージドノードであり、かつ Ping ステータスがオンラインであるもの
リファレンスの書きっぷり的にてっきり Ping ステータスがConnectionLost
のものも取得できると考えていたのですが、わたしが試行した範囲では実現できませんでした。(AWS CLI 2.9.1で試行。)
そのため、「マネージドノードだが停止中」というインスタンスはこのコマンドでは一覧に含まれてきません。今回はそこそこ停止中のインスタンスがあったのでaws ec2 describe-instances
を採用した、という背景がありました。(結果的に空振りでしたが。。)