この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
異常が発生したらSSM Run Commandを停止させたい
こんにちは、のんピ(@non____97)です。
皆さんは異常が発生したらSSM Run Commandの実行を停止させたいと思ったことはありますか? 私はあります。
例えば、CPUやメモリの使用率が閾値を超えた場合に負荷をかけないように処理を停止させたい時もあると思います。他にも接続先のFSx for ONTAPのボリュームの空き容量が少なくなった場合に、これ以上書き込まないように処理を停止させるといったシナリオもあると思います。
今回のアップデートでAWS Systems Manager の処理を CloudWatch アラームで制御できるようになりました。
CloudWatch メトリクスの状況に応じて処理を制御できるようになったのは嬉しいですね。
SSMのドキュメントの更新履歴を確認したところ、CloudWatch アラームの設定ができるSSMの処理は以下のようです。
- Run Command
- Automation
- State Manager
- Maintenance Windows
You can now implement additional control when running automations and commands by using CloudWatch alarms. A CloudWatch alarm can also be added to an automation or command when it is registered with a State Manager association or maintenance window task. By applying a composite CloudWatch alarm to an automation or command, you can control when an automation or command stops based on the metric you define. For more information about applying a CloudWatch alarm to an automation or command see the following procedures:
早速試してみたので紹介します。
2022/11/15追記 AWS公式ブログにもこちらの機能を紹介している記事が投稿されていました。併せてご覧下さい。
いきなりまとめ
- CloudWatch アラームの設定ができるSSMの処理は以下の通り
- Run Command
- Automation
- State Manager
- Maintenance Windows
- SSM Run Commandにアラーム状態になっているCloudWatch アラームを設定した場合は、実行できない
- SSM Run CommandにCloudWatch アラームを設定し、アラーム状態になった場合は
FailedDueToAlarm
で失敗する- アラーム状態になったことによって失敗した場合、途中の標準出力はSSM Run CommandのコンソールやCloudWatch Logsで確認できない
やってみた
検証のシナリオ
検証環境は以下の通りです。
EC2インスタンスのCPU利用率のメトリクスに対してCloudWatch アラームを作成しておきます。SSM Run Command実行中にCPUに負荷をかけた場合にどのような挙動をするのか確認します。
CloudWatch アラームの作成
CloudWatch アラームの作成をします。
5分間の最大CPU使用率が15%以上になったら、アラーム状態になるように作成しました。
EC2インスタンスのCPU使用率を取得できていることを確認します。
SSM Run Commandの実行
EC2インスタンスに対してSSM Run Commandを実行します。
実行するコマンドは1秒ごとに現在の日時を標準出力するシェルスクリプトです。
while true; do
date
sleep 1s
done
ドキュメントでAWS-RunShellScript
を選択して、コマンドのパラメーターとして先ほどのシェルスクリプトを設定します。
事前に用意しておいたEC2インスタンスをターゲットとして指定します。
先に作成したCloudWatch アラームを指定します。
Continue command if alarm status is unavailable
を有効にすることで、CloudWatch アラームの状態を取得できない場合は実行を停止せずに継続させるようなので有効化しておきます。
実行
をクリックして、ステータスが進行中
であることを確認します。
CloudWatch アラームをアラーム状態にする
SSM Run Command実行中にEC2インスタンスのCPUに負荷をかけて、CloudWatch アラームをアラーム状態にします。
# yes コマンドを並列で実行
$ yes > /dev/null &
[1] 2909
$ yes > /dev/null &
[2] 2910
$ yes > /dev/null &
[3] 2911
$ yes > /dev/null &
[4] 2912
$ yes > /dev/null &
[5] 2917
# アクティブなジョブの確認
$ jobs
[1] Running yes > /dev/null &
[2] Running yes > /dev/null &
[3] Running yes > /dev/null &
[4]- Running yes > /dev/null &
[5]+ Running yes > /dev/null &
CPU使用率が100%近くになり、CloudWatch アラームがアラーム状態になったことを確認します。
SSM Run Commandのステータスを確認すると、失敗になっていました。詳細なステータスはFailedDueToAlarm
となっていますね。
どのタイミングで失敗したのか確認するために出力結果を確認します。しかし、Output
にもError
も空欄になっています。
自分で実行をキャンセルした場合やexit 1
で終了させた場合は途中の処理も出力結果に表示されます。
- 自分で実行をキャンセルした場合
exit 1
で終了させた場合
また、CloudWatch Logsに出力するよう設定し直して、再実行してもCloudWatch Logsには出力されませんでした。
CloudWatch アラームがアラーム状態になったことによる実行の失敗時にはAWS側からどこまで処理が実行されたか確認することができないようです。そのため、どの処理まで完了したのか追いたい場合は、実行するコマンドでログファイルに実行結果を出力する必要がありそうです。
CloudWatch アラームがアラーム状態の場合は実行できるのか
次にCloudWatch アラームがアラーム状態の場合は実行できるのかも確認してみます。
コマンドの再実行
をクリックして再実行してみます。
すると、The following Cloudwatch alarm(s) were not in a compliant state: CPUUtilizationAlarm in state: ALARM
とエラーになり実行できませんでした。
CloudTrailのイベントを確認すると、こちらの実行失敗が記録されていました。
{
"eventVersion": "1.08",
"userIdentity": {
"type": "AssumedRole",
"principalId": "AROA6KUFAVPUZTMI6DMFH:<IAMロール名>",
"arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/<IAMユーザー名>/<IAMロール名>",
"accountId": "<AWSアカウントID>",
"accessKeyId": "ASIA6KUFAVPU2APCPP5G",
"sessionContext": {
"sessionIssuer": {
"type": "Role",
"principalId": "AROA6KUFAVPUZTMI6DMFH",
"arn": "arn:aws:iam::<AWSアカウントID>:role/<IAMロール名>",
"accountId": "<AWSアカウントID>",
"userName": "<IAMユーザー名>"
},
"webIdFederationData": {},
"attributes": {
"creationDate": "2022-10-02T06:21:08Z",
"mfaAuthenticated": "true"
}
}
},
"eventTime": "2022-10-02T07:20:17Z",
"eventSource": "ssm.amazonaws.com",
"eventName": "SendCommand",
"awsRegion": "us-east-1",
"sourceIPAddress": "AWS Internal",
"userAgent": "AWS Internal",
"errorCode": "ValidationException",
"errorMessage": "The following Cloudwatch alarm(s) were not in a compliant state: CPUUtilizationAlarm in state: ALARM",
"requestParameters": {
"targets": [
{
"key": "InstanceIds",
"values": [
"i-0e887a5db1ddcdc1a"
]
}
],
"documentName": "AWS-RunShellScript",
"documentVersion": "1",
"timeoutSeconds": 600,
"parameters": "HIDDEN_DUE_TO_SECURITY_REASONS",
"outputS3Region": "us-east-1",
"maxConcurrency": "50",
"maxErrors": "0",
"interactive": false,
"alarmConfiguration": {
"ignorePollAlarmFailure": true,
"alarms": [
{
"name": "CPUUtilizationAlarm"
}
]
}
},
"responseElements": null,
"requestID": "f569695e-05c3-4d79-b2af-31d42554d3e1",
"eventID": "0069029b-4594-4b9e-8b45-bad77b4fdc73",
"readOnly": false,
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "<AWSアカウントID>",
"eventCategory": "Management",
"sessionCredentialFromConsole": "true"
}
アラーム状態であれば、そもそも実行できないという挙動はありがたいですね。上手く使えば、スクリプトの最初に本当にスクリプトを実行しても良い状態か確認する手間を省くことができそうです。
Systems Managerの制御の幅が広がりました
AWS Systems Manager の処理を CloudWatch アラームで制御できるようになったアップデートを紹介しました。
SSMの制御の幅が広がり、より使いやすくなったと思います。
今回は試しませんでしたが、Maintenance Windowsと組み合わせれば、メンテナンス可能な時間だけではなく状態も指定できるため、運用するときにかなり助かりそうです。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!