[アップデート] AWS Systems Manager の処理を CloudWatch アラームで制御できるようになりました

Systems Managerの制御の幅が広がりました
2022.10.02

異常が発生したら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:

Document history - AWS Systems Manager

早速試してみたので紹介します。

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使用率を取得できていることを確認します。

作成したCloudWatch アラームの確認

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 alarm - optional

実行をクリックして、ステータスが進行中であることを確認します。

コマンド ID- f6354efa-48bf-4216-bb2a-1a14fe8732ce が正常に送信されました

CloudWatch アラームをアラーム状態にする

SSM Run Command実行中にEC2インスタンスのCPUに負荷をかけて、CloudWatch アラームをアラーム状態にします。

# yes コマンドを並列で実行
$ yes > /dev/null &
[1] 2909
sh-4.2$ yes > /dev/null &
[2] 2910
sh-4.2$ yes > /dev/null &
[3] 2911
sh-4.2$ yes > /dev/null &
[4] 2912
sh-4.2$ 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となっていますね。

FailedDueToAlarm

どのタイミングで失敗したのか確認するために出力結果を確認します。しかし、OutputにもErrorも空欄になっています。

出力の表示

自分で実行をキャンセルした場合やexit 1で終了させた場合は途中の処理も出力結果に表示されます。

  • 自分で実行をキャンセルした場合 自分でキャンセルした場合の出力結果
  • 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とエラーになり実行できませんでした。

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)でした!