AWS Systems Manager Maintenance Windows を使って定期的なソフトウェアアップデートを行う

2024.02.28

はじめに

AWS 事業本部コンサルティング部のイシザワです。

EC2 上のシステムを運用するにあたって SSM Agent や CloudWatch Agent などのソフトウェアを定期的にアップデートすることが推奨されています。

この定期的なアップデートを AWS Systems Manager Maintenance Windows を利用して実現します。

AWS Systems Manager Maintenance Windows とは

AWS Systems Manager Maintenance Windows は Systems Manager の機能の一つで、EC2 や オンプレミスのシステムへのパッチ適用やソフトウェアアップデートなどのアクションをスケジュールする機能です。

マネージドサービスでは OS やミドルウェアを AWS が管理しているため、それらのパッチ適用やアップデートは自動で行われます。 例えば RDS では利用者がメンテナンスウィンドウを設定することで、メンテナンスウィンドウ中に OS や DB エンジンのアップデートが行われます。

一方、EC2 は OS やミドルウェアを利用者が管理しているため、ソフトウェアアップデートやメンテナンスタスクのスケジュールの管理も利用者が行う必要があります。 特に複数台のサーバを利用していると、各サーバーのメンテナンス時間の管理やタスクの管理で運用に大きな負荷が出てきます。

Systems Manager Maintenance Windows を使うと、複数のターゲットに対してメンテナンスタスクを実行する時間枠を設定することができ、メンテナンスタスク管理の運用負荷を抑えることが出来ます。 利用者独自のメンテナンスウィンドウを作成するサービスと言い換えても良いかもしれません。

なお、Systems Manager Maintenance Windows は Systems Manager の機能を利用するため、対象のシステムには SSM Agent がインストールされている必要があります。

事前準備

今回は一台の EC2 Windows インスタンスの SSM Agent と CloudWatch Agent の更新を行います。

EC2 Windows インスタンスを作成して、少し古めの SSM Agent と CloudWatch Agent をインストールします。 インストール後の各ソフトウェアのバージョンと設定内容は以下の通りです。

> & "C:\Program Files\Amazon\SSM\amazon-ssm-agent.exe" -version
SSM Agent version: 3.2.1798.0

> & $Env:ProgramFiles\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1 -m ec2 -a status
{
  "status": "running",
  "starttime": "2024-02-27T07:39:24",
  "configstatus": "configured",
  "version": "1.300028.4b233"
}

> Get-Content $Env:ProgramData\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent.toml
[agent]
  collection_jitter = "0s"
  debug = false
  flush_interval = "1s"
  flush_jitter = "0s"
  hostname = ""
  interval = "60s"
  logfile = "C:\\ProgramData\\Amazon\\AmazonCloudWatchAgent\\Logs\\amazon-cloudwatch-agent.log"
  logtarget = "lumberjack"
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  omit_hostname = false
  precision = ""
  quiet = false
  round_interval = false

[inputs]

  [[inputs.statsd]]
    interval = "60s"
    parse_data_dog_tags = true
    service_address = ":8125"
    [inputs.statsd.tags]
      "aws:AggregationInterval" = "60s"

[outputs]

  [[outputs.cloudwatch]]

手順

Systems Manager のコンソールを開き、左ペインの「変更管理 > メンテナンスウィンドウ」を選択します。

「メンテナンスウィンドウの作成」をクリックします。

「メンテナンスウィンドウの作成」ウィザードに移動します。「メンテナンスウィンドウの詳細の入力」で名前と説明を記入します。

「未登録ターゲットを許可する」にチェックを入れると、ターゲット(後述)に登録していないインスタンスをタスクの実行対象に選択することができます。

「スケジュール」でタスクを実行するスケジュールを設定します。 Cron や Rate を利用することでができ、「期間」でメンテナンスウィンドウの長さを設定します。

「タスクの開始を停止する」でカットオフ期間を設定することが出来ます。例えばメンテナンスウィンドウの長さを3時間、カットオフ期間を1時間とすると、メンテナンスウィンドウが始まってはじめの2時間はタスクが新規に開始されますが、最後の1時間はタスクが開始されません。 今回のソフトウェアアップデートは数分で終わるのでカットオフ期間は設定しないことにしました。

これらの設定が完了したら「メンテナンスウィンドウの作成」をクリックします。

メンテナンスウィンドウが作成されたら、次にメンテナンスタスクを行うターゲットの登録を行います。 ウィンドウID左のチェックボックスにチェックを入れて、「アクション > ターゲットの登録」をクリックします。

「Register Target」ウィザードに移動するので、ターゲットの詳細情報を入力します。

ターゲットの選択では、インスタンスのタグ値で指定するか、インスタンスを直接指定するか、Resource Groups を選択するかを選べます。 今回はインスタンスを直接指定しました。設定が済んだら「Register target」をクリックします。

ターゲットの登録が完了したら、次に実行するタスクの登録を行います。

まずは SSM Agent のアップデートを行うタスクを登録します。 ウィンドウの詳細画面の「タスク」タブを選択し、「タスクの登録 > Run Command タスクの登録」をクリックします。

今回は単純な処理なので Run Command タスクを登録します。SSM Automation ランブックや Lambda 関数や Step Functions ステートマシンもタスクとして登録できるので、複雑な処理が必要な場合はこちらも選択肢になると思います。

「Run Command タスクの登録」ウィザードに移動するので、タスクの詳細情報を入力します。 「New task invocation cutoff」を有効にすることでカットオフ期間にタスクが開始されなくなります。

コマンドドキュメントより「AWS-UpdateSSMAgent」を選択し、「タスク優先度」を1とします。 「タスク優先度」はタスクの処理順を決定する値で、小さい方が優先度が高いです。タスクは優先度順に逐次実行され、同一の優先度のタスクどうしは並列実行されます。 今回の場合は処理どうしは独立しているため並列実行します。

タスクの実行対象に先ほど登録したターゲットを選択します。 レート制御はタスクを実行するターゲットの同時実行数を設定できます。

IAM サービスロールを設定することでユーザー設定の権限でタスクを実行できます。デフォルトで service-linked ロールの AWSServiceRoleForAmazonSSM の権限でタスクが実行されます。 SSM の機能のみを使う場合はこれで十分なので今回は設定しません。他のAWSサービスを使いたい場合や、ガバナンスのため権限を絞りたい場合は IAM ロールを設定します。

出力オプションでログの出力設定を、SNS通知でコマンドの経過の通知を設定することが出来ます。

パラメータで Run Command のパラメータを設定します。 今回は以下の値を設定します。

項目 備考
Version 最新のバージョンをインストールするため空白
Allow Downgrade false デフォルト値
コメント 設定無し
タイムアウト 600 デフォルト値

CloudWatch アラームの設定で失敗した場合にアラームを発報することができます。

設定が完了したら「Run Command タスクの登録」をクリックします。

登録が完了したら、引き続き Cloud Watch Agent のアップデートを行うタスクを登録します。

前と同様に「タスクの登録 > Run Command タスクの登録」をクリックし、タスクの詳細情報を入力します。

コマンドドキュメントに「AWS-ConfigureAWSPackage」を選択し、タスク優先度を1とします。 SSM Agent のアップデートタスクのタスク優先度も1なので、これらのタスクは並列実行されます。

パラメータに以下を設定します。

項目 備考
Action Install
Installation Type Uninstall and reinstall
Name AmazonCloudWatchAgent
Version 最新のバージョンをインストールするため空白
Additional Arguments {} デフォルト値
コメント 設定無し
タイムアウト 600 デフォルト値

他の項目は前回と同様に設定し、タスクを登録します。

登録後、メンテナンスウィンドウ詳細画面の「履歴」タブよりタスクの実行履歴が確認できます。

タスクの実行後、インスタンスにログインしてソフトウェアのバージョンがアップデートされていることが確認できます。

> & "C:\Program Files\Amazon\SSM\amazon-ssm-agent.exe" -version
SSM Agent version: 3.2.2222.0

> & $Env:ProgramFiles\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1 -m ec2 -a status
{
  "status": "running",
  "starttime": "2024-02-27T07:30:28",
  "configstatus": "configured",
  "version": "1.300033.0b462"
}

> Get-Content $Env:ProgramData\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent.toml
[agent]
  collection_jitter = "0s"
  debug = false
  flush_interval = "1s"
  flush_jitter = "0s"
  hostname = ""
  interval = "60s"
  logfile = "C:\\ProgramData\\Amazon\\AmazonCloudWatchAgent\\Logs\\amazon-cloudwatch-agent.log"
  logtarget = "lumberjack"
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  omit_hostname = false
  precision = ""
  quiet = false
  round_interval = false

[inputs]

  [[inputs.statsd]]
    interval = "60s"
    parse_data_dog_tags = true
    service_address = ":8125"
    [inputs.statsd.tags]
      "aws:AggregationInterval" = "60s"

[outputs]

  [[outputs.cloudwatch]]

おわりに

AWS Systems Manager Maintenance Windows で利用し、ソフトウェアアップデートを行うメンテナンスタスクの設定を行いました。

今回は単純なソフトウェアアップデートを行いましたが、例えば Patch Manager と組み合わせることでメンテナンスウィンドウ中に OS のバージョンアップを行うこともできます。

ただし、メンテナンスウィンドウはあくまでタスクの開始時間をスケジュールする機能であり、タスクの終了時間を保障する機能ではありません。 Windows Update などの実行時間がかかる処理を行う場合には、メンテナンスウィンドウ中に処理が終了するのかを十分検証する必要があります。 時間内に完了するのが難しい場合は、Systems Manager Maintenance Windows ではなくシステムを並列化してローリングアップデートを行うなどの別の手段を考えた方が良いかもしれません。

この記事が誰かの助けになれば幸いです。