Azure Metadata Service: Windows VM のScheduled Events

適用対象: ✔️ Windows VM ✔️ フレキシブル スケール セット ✔️ 均一スケール セット

スケジュールされたイベントとは、仮想マシン (VM) のメンテナンスに備えるための時間をアプリケーションに与える Azure Metadata Service です。 今後のメンテナンス イベント (再起動など) に関する情報を提供することで、アプリケーションがイベントの準備を行い、中断を制限できるようにします。 このサービスは、Windows および Linux の、PaaS と IaaS を含むすべての Azure Virtual Machine の種類で利用できます。

Linux のScheduled Events の詳細については、Linux VM のScheduled Events に関する記事をご覧ください。

スケジュール化されたイベントでは、今後のイベントに関するプロアクティブ通知が提供されます。既に発生しているイベントに関する事後対応情報については、「Azure Resource Graph の VM 可用性に関する情報」および「Azure 仮想マシンの可用性アラート ルールを作成する」を参照してください。

注意

Scheduled Events は、すべての Azure リージョンで一般公開されています。 最新リリースについては、「利用可能なバージョンとリージョン」をご覧ください。

Scheduled Events を使用する理由

多くのアプリケーションに、VM のメンテナンスに備える時間が得られるメリットがあります。 この時間を使用して、可用性、信頼性、およびサービスを向上させる、次のようなアプリケーション固有のタスクを実行できます。

  • チェックポイントと復元
  • 接続のドレイン
  • プライマリ レプリカのフェールオーバー
  • ロード バランサー プールからの削除
  • イベント ログ
  • グレースフル シャットダウン

Scheduled Events を使用すると、アプリケーションはメンテナンスが行われる時期を検出し、その影響を制限するタスクをトリガーできます。

Scheduled Events は、次のユース ケースでイベントを提供します。

基本操作

Metadata Service では、VM 内部からアクセスできる REST エンドポイントを使用した VM の実行に関する情報が公開されます。 情報は、VM の外部に公開されないように、ルーティング不可能な IP 経由で提供されます。

Scope

スケジュールされたイベントは以下に配信され、以下が確認できます。

注意

ファブリック コントローラー (FC) テナント内のすべての仮想マシン (VM) の Scheduled Events は、FC テナント内のすべての VM に配信されます。 FC テナントは、可用性ゾーンの使用に関係なく、スタンドアロン VM、クラウド サービス全体、可用性セット全体、および仮想マシン Scale Sets (VMSS) の配置グループに相当します。

そのため、イベント内の Resources フィールドをチェックして、影響を受ける VM を特定する必要があります。

エンドポイントの検出

VNET が有効な VM の場合は、静的でルーティング不可能な IP アドレス 169.254.169.254 から Metadata Service を利用できます。 スケジュールされたイベントの最新バージョンのフル エンドポイントは次のとおりです。

http://169.254.169.254/metadata/scheduledevents?api-version=2020-07-01

VM が仮想ネットワーク内で作成されていない場合 (クラウド サービスと従来の VM の既定のケース)、使用する IP アドレスを検出する追加のロジックが必要となります。 ホスト エンドポイントの検出方法の詳細については、このサンプルを参照してください。

利用可能なバージョンとリージョン

スケジュールされたイベントのサービスは、バージョンによって管理されています。 バージョンは必須で、現在のバージョンは 2020-07-01 です。

Version リリースの種類 リージョン リリース ノート
2020-07-01 一般公開 All
  • イベントの期間のサポートを追加しました
  • 2019-08-01 一般公開 All
  • EventSource のサポートを追加しました
  • 2019-04-01 一般公開 All
  • イベントの説明のサポートを追加しました
  • 2019-01-01 一般公開 All
  • Virtual Machine Scale Sets の EventType "Terminate" のサポートを追加しました
  • 2017-11-01 一般公開 All
  • スポット VM 削除の EventType "Preempt" のサポートを追加しました
  • 2017-08-01 一般公開 All
  • IaaS VM のリソース名から先頭のアンダースコアを削除しました
  • すべての要求にメタデータ ヘッダー要件を適用しました
  • 2017-03-01 プレビュー All
  • 最初のリリース
  • 注意

    Scheduled Events の前のプレビュー リリースでは、api-version として {latest} がサポートされていました。 この形式はサポートされなくなり、今後非推奨となる予定です。

    Scheduled Events の有効化と無効化

    Scheduled Events は、ユーザーが初めてイベントを要求したときに、サービスに対して有効になります。 最初の呼び出しでは、最大 2 分の応答遅延が発生すると予想されます。 スケジュール化されたイベントは、サービスで 24 時間エンドポイントへの要求が行われないと、サービスに対して無効になります。

    ユーザー開始メンテナンス

    ユーザーが Azure Portal、API、CLI または PowerShell を使用して開始した VM のメンテナンスによって、スケジュールされたイベントが発生します。 これによって、アプリケーションでメンテナンス準備ロジックをテストすることができ、アプリケーションでは、ユーザーが開始したメンテナンスの準備をすることができます。

    VM を再起動すると、型 Reboot のイベントがスケジュールされます。 VM を再デプロイすると、型 Redeploy のイベントがスケジュールされています。 通常、ユーザー イベント ソースを含むイベントは、ユーザーが開始するアクションの遅延を回避するために、すぐに承認できます。 プライマリ VM が応答しなくなる場合に備えて、プライマリ VM とセカンダリ VM を通信させ、ユーザーが生成したスケジュールされたイベントが承認されるようにすることをお勧めします。 イベントをすぐに承認すると、アプリケーションを適切な状態に回復する遅延を防ぐことができます。

    VMSS ゲスト OS のアップグレードまたは再イメージ化のスケジュール化されたイベントは、メモリ保持更新をサポートする汎用 VM サイズでのみサポートされます。 G、M、N、および H シリーズでは機能しません。 VMSS ゲスト OS のアップグレードおよび再イメージ化のスケジュール化されたイベントは既定で無効になっています。 サポートされる VM サイズでこれらの操作のスケジュール化されたイベントを有効にするには、まず OSImageNotificationProfile を使用してそれらを有効にします。

    API の使用

    概要

    Scheduled Events の処理、準備、回復には、2 つの主要なコンポーネントがあります。 顧客に影響を与える現在のイベントはすべて、IMDS Scheduled Events エンドポイントを介して使用できます。 イベントが終了状態に達すると、イベントの一覧から削除されます。 次の図は、1 つのスケジュールされたイベントで発生する可能性があるさまざまな状態遷移を示しています:

    スケジュール化されたイベントが取る様々な状態遷移を示す状態図。

    EventStatus:"Scheduled" 状態のイベントの場合は、ワークロードを準備するための手順を実行する必要があります。 準備が完了したら、スケジュール化されたイベント API を使用してイベントを承認する必要があります。 それ以外の場合、NotBefore 時間に達すると、イベントは自動的に承認されます。 VM が共有インフラストラクチャ上にある場合、システムは、同じハードウェア上の他のすべてのテナントもジョブまたはタイムアウトを承認するまで待機します。 影響を受けるすべての VM から承認が収集されるか、NotBefore 時間に達すると、Azure は EventStatus:"Started" を使用して新しいスケジュールされたイベント ペイロードを生成し、メンテナンス イベントの開始をトリガーします。 イベントが終了状態に達すると、テナントが VM を復旧するためのシグナルとして機能するイベントの一覧から削除されます。"

    アプリケーションでスケジュールされたイベントを読み取って管理する方法を示す疑似コードを次に示します:

    current_list_of_scheduled_events = get_latest_from_se_endpoint()
    #prepare for new events
    for each event in current_list_of_scheduled_events:
      if event not in previous_list_of_scheduled_events:
        prepare_for_event(event)
    #recover from completed events
    for each event in previous_list_of_scheduled_events:
      if event not in current_list_of_scheduled_events:
        receover_from_event(event)
    #prepare for future jobs
    previous_list_of_scheduled_events = current_list_of_scheduled_events
    

    スケジュール化されたイベントは高可用性要件を持つアプリケーションでよく使用されるため、考慮すべき例外的なケースがいくつかあります:

    1. スケジュール化されたイベントが完了し、配列から削除されると、別の EventStatus:"Scheduled" イベントを含む新しいイベントがなければ、それ以上の影響はありません
    2. Azure はフリート全体のメンテナンス操作を監視し、まれにメンテナンス操作が適用されるリスクが高すぎると判断します。 その場合、スケジュール化されたイベントは "Scheduled" から直接 events 配列から削除されます
    3. ハードウェア障害が発生した場合、Azure は "Scheduled" 状態をバイパスし、すぐに EventStatus:"Started" 状態に移行します。
    4. イベントはまだ EventStatus:"Started" 状態ですが、スケジュール化されたイベントでアドバタイズされた期間よりも短い期間の影響が発生する可能性があります。

    Azure の可用性保証の一環として、異なる障害ドメイン内の VM は、定期的なメンテナンス操作によって同時に影響を受けることはありません。 ただし、操作が次々にシリアル化される場合があります。 1 つの障害ドメイン内の VM は、別の障害ドメインのメンテナンスが完了した直後に、EventStatus:"Scheduled" でスケジュールされたイベントを受信できます。 選択したアーキテクチャに関係なく、VM に対して保留中の新しいイベントを常にチェックし続けます。

    イベントの正確なタイミングは異なりますが、次の図は、一般的なメンテナンス操作の進め方に関する大まかなガイドラインを示しています:

    • EventStatus:"Scheduled" から Approval Timeout: 15 分
    • 影響時間: 7 秒
    • EventStatus:"Started" から Completed (イベント配列から削除されたイベント): 10 分

    スケジュール化されたイベントのフローを示すタイムライン図。

    ヘッダー

    メタデータ サービスのクエリを実行するときには、要求が意図せずリダイレクトされないように、ヘッダー Metadata:true を指定する必要があります。 Metadata:true ヘッダーは、スケジュールされたイベントのすべての要求で必要です。 要求にヘッダーを含めないと、メタデータ サービスから Bad Request (無効な要求) という応答があります。

    イベントのクエリ

    次の呼び出しを行うと、スケジュールされたイベントのクエリを実行できます。

    Bash のサンプル

    curl -H Metadata:true http://169.254.169.254/metadata/scheduledevents?api-version=2020-07-01
    

    PowerShell のサンプル

    Invoke-RestMethod -Headers @{"Metadata"="true"} -Method GET -Uri "http://169.254.169.254/metadata/scheduledevents?api-version=2020-07-01" | ConvertTo-Json -Depth 64
    

    Python のサンプル

    import json
    import requests
    
    metadata_url ="http://169.254.169.254/metadata/scheduledevents"
    header = {'Metadata' : 'true'}
    query_params = {'api-version':'2020-07-01'}
    
    def get_scheduled_events():           
        resp = requests.get(metadata_url, headers = header, params = query_params)
        data = resp.json()
        return data
    
    

    応答には、スケジュールされたイベントの配列が含まれています。 空の配列は、現在スケジュールされているイベントがないことを意味します。 スケジュールされたイベントがある場合は、応答にイベントの配列が含まれます。

    {
        "DocumentIncarnation": {IncarnationID},
        "Events": [
            {
                "EventId": {eventID},
                "EventType": "Reboot" | "Redeploy" | "Freeze" | "Preempt" | "Terminate",
                "ResourceType": "VirtualMachine",
                "Resources": [{resourceName}],
                "EventStatus": "Scheduled" | "Started",
                "NotBefore": {timeInUTC},       
                "Description": {eventDescription},
                "EventSource" : "Platform" | "User",
                "DurationInSeconds" : {timeInSeconds},
            }
        ]
    }
    

    イベントのプロパティ

    プロパティ 説明
    Document Incarnation イベント配列が変更されたときに増加する整数。 同じインカネーションを持つドキュメントには同じイベント情報が含まれており、イベントが変更されると、インカネーションが増加されます。
    EventId このイベントのグローバル一意識別子。

    例:
    • 602d9444-d2cd-49c7-8624-8643e7171297
    EventType このイベントによって発生する影響。

    値:
    • Freeze:仮想マシンは数秒間の一時停止がスケジュールされています。 CPU とネットワーク接続が中断する場合がありますが、メモリや開いているファイルへの影響はありません。
    • Reboot:Virtual Machine は再起動がスケジュールされています (非永続メモリは失われます)。
    • Redeploy:Virtual Machine は別のノードへの移動がスケジュールされています (一時ディスクは失われます)。
    • Preempt:スポット仮想マシンが削除されています(一時ディスクは失われています)。 このイベントはベスト エフォートで利用可能になります
    • Terminate:仮想マシンは削除がスケジュールされています。
    ResourceType このイベントが影響を与えるリソースの種類。

    値:
    • VirtualMachine
    リソース このイベントが影響を与えるリソースの一覧。

    例:
    • ["FrontEnd_IN_0", "BackEnd_IN_0"]
    EventStatus このイベントの状態。

    値:
    • Scheduled:このイベントは、NotBefore プロパティに指定された時間が経過した後で開始するようにスケジュールされています。
    • Started:このイベントは開始されています。
    Completed や類似の状態が提供されることはありません。 イベントが完了すると、イベントは返されなくなります。
    NotBefore このイベントが開始される時間。 このイベントは、この時刻より前に開始されないことが保証されます。 イベントが既に開始されている場合は空白になります

    例:
    • Mon, 19 Sep 2016 18:29:47 GMT
    説明 このイベントの説明。

    例:
    • ホスト サーバーのメンテナンス中です。
    EventSource イベントのイニシエーター。

    例:
    • Platform:このイベントは、プラットフォームによって開始されています。
    • User:このイベントは、ユーザーによって開始されています。
    DurationInSeconds イベントによって発生する中断の予想される期間。

    例:
    • 9: イベントによって発生する中断は 9 秒間続きます。
    • 0: イベントによって VM が中断されたり、その可用性が影響を受けたりしません (ネットワークへの更新など)。
    • -1: 影響期間が不明な場合または適用されない場合に使用される既定値。

    イベントのスケジューリング

    各イベントは、スケジュールされているイベントの種類に基づいて、将来の最小値の時間でスケジュールされます。 この時間は、イベントの NotBefore プロパティに反映されます。

    EventType 最小値の通知
    Freeze 約 15 分
    再起動 約 15 分
    Redeploy 10 分
    Terminate ユーザーが構成可能:5 から 15 分

    イベントはスケジュールされると、それが承認されるか、または NotBefore 時間が経過した後に、Started 状態に移動します。 ただし、まれに、操作が開始される前に Azure によって取り消されます。 その場合、イベントは Events 配列から削除され、影響は、以前にスケジュールしたようには発生しません。

    注意

    Azure では、劣化したハードウェアに起因するホストの故障を予測することが可能になり、移行をスケジュールすることでサービスの中断を軽減しようとすることがあります。 影響を受ける仮想マシンには、スケジュールされているイベントと NotBefore が届きます。これは通常、2、3 日先になります。 実際の時間は、予測された故障のリスク評価によって異なります。 Azure では、可能であれば、7 日前に通知を行いますが、実際の時間はさまざまであり、ハードウェアが今にも故障する可能性が高い場合、7 日より短くなることがあります。 システムによって開始される移行の前にハードウェアで障害が発生した場合に備えて、サービスのリスクを最小限に抑えるために、できるだけ早く仮想マシンをご自身で再デプロイすることをお勧めします。

    注意

    ホスト ノードでハードウェア障害が発生した場合、Azure では最小通知期間を無視して、影響を受けた仮想マシンの復旧プロセスを直ちに開始します。 これにより、影響を受けた VM が応答できない場合の復旧時間が短縮されます。 復旧プロセス中に、影響を受けるすべての VM に対して、EventType = Reboot および EventStatus = Started が設定されたイベントが作成されます。

    ポーリング頻度

    更新のエンドポイントは、任意の頻度でポーリングできます。 ただし、要求間の間隔が長くなるほど、発生するイベントに対応するのが遅くなる可能性があります。 ほとんどのイベントは、5 - 15 分前に通知されますが、場合によっては、通知がわずか 30 秒前ということもあります。 対策を講じるための時間をできるだけ多く確保するために、1 秒に 1 回サービスをポーリングすることをお勧めします。

    イベントの開始

    今後予定されているイベントを確認し、グレースフル シャットダウンのロジックを完了すると、EventId を使用してメタデータ サービスに POST 呼び出しを行うことにより、未処理のイベントを承認できます。 この呼び出しは、通知の最小時間を短縮できる (可能な場合) ことが Azure に示されます。 イベントは、承認されてもすぐには開始されない場合があります。場合によっては、イベントを続行する前に、ノードでホストされているすべての VM の承認が Azure で必要とされる場合があります。

    次に示すのは、POST 要求本文で求められている JSON のサンプルです。 要求には、StartRequests の一覧を含める必要があります。 各 StartRequest には、迅速に進める必要があるイベントの EventId が含まれます。

    {
    	"StartRequests" : [
    		{
    			"EventId": {EventId}
    		}
    	]
    }
    

    イベントが別の VM で既に承認されていた場合でも、有効なイベント ID を渡すと、サービスは成功コード 200 を常に返します。 400 エラー コードは、要求ヘッダーまたはペイロードの形式が正しくないことを示します。

    Note

    イベントは、POST メッセージまたは NotBefore 時間の経過によって許可されない限り続行されません。 これには、Azure portal からの VM の再起動などのユーザーによってトリガーされたイベントが含まれます。

    Bash のサンプル

    curl -H Metadata:true -X POST -d '{"StartRequests": [{"EventId": "f020ba2e-3bc0-4c40-a10b-86575a9eabd5"}]}' http://169.254.169.254/metadata/scheduledevents?api-version=2020-07-01
    

    PowerShell のサンプル

    Invoke-RestMethod -Headers @{"Metadata" = "true"} -Method POST -body '{"StartRequests": [{"EventId": "5DD55B64-45AD-49D3-BBC9-F57D4EA97BD7"}]}' -Uri http://169.254.169.254/metadata/scheduledevents?api-version=2020-07-01 | ConvertTo-Json -Depth 64
    

    Python のサンプル

    import json
    import requests
    
    def confirm_scheduled_event(event_id):  
       # This payload confirms a single event with id event_id
       payload = json.dumps({"StartRequests": [{"EventId": event_id }]})
       response = requests.post("http://169.254.169.254/metadata/scheduledevents", 
                                headers =  {'Metadata' : 'true'}, 
                                params = {'api-version':'2020-07-01'}, 
                                data = payload)    
       return response.status_code
    

    注意

    イベントの受信確認により、イベントを受信確認した VM だけでなく、イベント内のすべての Resources でイベントが続行されます。 そのため、受信確認を調整するリーダーを選択できます。これは、Resources フィールド内の最初のマシンと同様に簡単です。

    応答の例

    次のイベントは、ライブ状態で別のノードに以降された 2 つの VM で発生した一例です。

    DocumentIncarnation は、Events に新しい情報があるたびに変化していきます。 イベントの承認により、WestNO_0 と WestNO_1 の両方で凍結を続行できます。 -1 の DurationInSeconds は、操作にどれほどの時間がかかるか、プラットフォームで認識されないことを示します。

    {
        "DocumentIncarnation":  1,
        "Events":  [
                   ]
    }
    
    {
        "DocumentIncarnation":  2,
        "Events":  [
                       {
                           "EventId":  "C7061BAC-AFDC-4513-B24B-AA5F13A16123",
                           "EventStatus":  "Scheduled",
                           "EventType":  "Freeze",
                           "ResourceType":  "VirtualMachine",
                           "Resources":  [
                                             "WestNO_0",
                                             "WestNO_1"
                                         ],
                           "NotBefore":  "Mon, 11 Apr 2022 22:26:58 GMT",
                           "Description":  "Virtual machine is being paused because of a memory-preserving Live Migration operation.",
                           "EventSource":  "Platform",
                           "DurationInSeconds":  5
                       }
                   ]
    }
    
    {
        "DocumentIncarnation":  3,
        "Events":  [
                       {
                           "EventId":  "C7061BAC-AFDC-4513-B24B-AA5F13A16123",
                           "EventStatus":  "Started",
                           "EventType":  "Freeze",
                           "ResourceType":  "VirtualMachine",
                           "Resources":  [
                                             "WestNO_0",
                                             "WestNO_1"
                                         ],
                           "NotBefore":  "",
                           "Description":  "Virtual machine is being paused because of a memory-preserving Live Migration operation.",
                           "EventSource":  "Platform",
                           "DurationInSeconds":  5
                       }
                   ]
    }
    
    {
        "DocumentIncarnation":  4,
        "Events":  [
                   ]
    }
    
    

    Python サンプル

    次のサンプルでは、スケジュールされたイベントのメタデータ サービスにクエリを実行し、未処理の各イベントを承認しています。

    #!/usr/bin/python
    import json
    import requests
    from time import sleep
    
    # The URL to access the metadata service
    metadata_url ="http://169.254.169.254/metadata/scheduledevents"
    # This must be sent otherwise the request will be ignored
    header = {'Metadata' : 'true'}
    # Current version of the API
    query_params = {'api-version':'2020-07-01'}
    
    def get_scheduled_events():           
        resp = requests.get(metadata_url, headers = header, params = query_params)
        data = resp.json()
        return data
    
    def confirm_scheduled_event(event_id):  
        # This payload confirms a single event with id event_id
        # You can confirm multiple events in a single request if needed      
        payload = json.dumps({"StartRequests": [{"EventId": event_id }]})
        response = requests.post(metadata_url, 
                                headers= header,
                                params = query_params, 
                                data = payload)    
        return response.status_code
    
    def log(event): 
        # This is an optional placeholder for logging events to your system 
        print(event["Description"])
        return
    
    def advanced_sample(last_document_incarnation): 
        # Poll every second to see if there are new scheduled events to process
        # Since some events may have necessarily short warning periods, it is 
        # recommended to poll frequently
        found_document_incarnation = last_document_incarnation
        while (last_document_incarnation == found_document_incarnation):
            sleep(1)
            payload = get_scheduled_events()    
            found_document_incarnation = payload["DocumentIncarnation"]        
            
        # We recommend processing all events in a document together, 
        # even if you won't be actioning on them right away
        for event in payload["Events"]:
    
            # Events that have already started, logged for tracking
            if (event["EventStatus"] == "Started"):
                log(event)
                
            # Approve all user initiated events. These are typically created by an 
            # administrator and approving them immediately can help to avoid delays 
            # in admin actions
            elif (event["EventSource"] == "User"):
                confirm_scheduled_event(event["EventId"])            
                
            # For this application, freeze events less that 9 seconds are considered
            # no impact. This will immediately approve them
            elif (event["EventType"] == "Freeze" and 
                int(event["DurationInSeconds"]) >= 0  and 
                int(event["DurationInSeconds"]) < 9):
                confirm_scheduled_event(event["EventId"])
                
            # Events that may be impactful (eg. Reboot or redeploy) may need custom 
            # handling for your application
            else: 
                #TODO Custom handling for impactful events
                log(event)
        print("Processed events from document: " + str(found_document_incarnation))
        return found_document_incarnation
    
    def main():
        # This will track the last set of events seen 
        last_document_incarnation = "-1"
    
        input_text = "\
            Press 1 to poll for new events \n\
            Press 2 to exit \n "
        program_exit = False 
    
        while program_exit == False:
            user_input = input(input_text)    
            if (user_input == "1"):                        
                last_document_incarnation = advanced_sample(last_document_incarnation)
            elif (user_input == "2"):
                program_exit = True       
    
    if __name__ == '__main__':
        main()
    

    次のステップ