トレーニングと推論のワークロードを実行しているノードのホスト メンテナンスを行う

このドキュメントでは、Google Kubernetes Engine(GKE)クラスタ内のノードの基盤となる Compute Engine インスタンスのホスト メンテナンスを行う方法について説明します。このメンテナンスを積極的に管理する必要があるのは、GPU や TPU を搭載したインスタンスなど、ライブ マイグレーションが行われない特定のタイプの Compute Engine インスタンスのみです。このドキュメントで説明する戦略は、トレーニング ワークロードと推論ワークロードに適しています。個々のノードに対してホスト メンテナンスを手動で実行するだけでよい場合や、ワークロードが自動ホスト メンテナンスを許容できる場合は、GKE でホスト メンテナンスを実行する方法を理解するをご覧ください。

これらの戦略では、ノードのグループに対してホスト メンテナンスを実行し、必要に応じて GKE クラスタのアップグレードを開始します。

トレーニング ワークロードのノードなど、1 回のダウンタイムを許容できるワークロードのノードには、並列戦略を使用します。推論ワークロードのノードなど、リソースの大部分の可用性を維持しながら、ダウンタイムをバッチ処理できるワークロードのノードには、ローリング戦略を使用します。

並列戦略を使用してトレーニング ワークロードのノードを更新する

この戦略では、アクセラレータを使用するノードのグループに対して同時に変更が実行されます。この戦略は、トレーニング ワークロードに使用できます。また、グループ内のすべてのノードとそれらのノードで実行されるワークロードに対して、完全なダウンタイムの単一のウィンドウを設けることが、変更を実行する際の最も中断の少ない方法であるような、他のタイプのワークロードにも使用できます。

この戦略は、次の大まかな手順で行われます。

  1. ワークロードを停止する: ノードプールを選択し、そこで実行されているワークロードを停止するか、ワークロードを使用可能な他のノードに移動します。
  2. ホスト メンテナンスをトリガーする: 選択したすべてのノードにメンテナンス ラベルを同時に適用し、すべてのノードでプロセスが完了するまで待ちます。
  3. GKE バージョンをアップグレードする: ノードの GKE バージョンを変更します。
  4. ワークロードを再起動する: すべてのホストのメンテナンスとアップグレードが完了したら、ワークロードを再起動します。

以下の手順では、1 つのノードプールに変更を加えます。ただし、複数のノードプールに対して同時に変更を行うように手順を調整することもできます。これらの手順を開始する前に、このワークロードをこれらのノードで実行する必要がない時間が少なくとも数時間あることを確認してください。

基盤となる Compute Engine インスタンスと GKE ノードの両方で重要な変更を受け取る際の中断を最小限に抑えるには、このダウンタイム期間を使用してホスト メンテナンスと GKE バージョンのアップグレードの両方を実行します。ただし、GKE ノードのバージョンをアップグレードしない場合は、ホスト メンテナンスのみを実行できます。

始める前の検討事項

始める前に、以下の注意事項を確認してください。

  • ワークロードの再デプロイを回避する: PodDisruptionBudgets による不要な遅延を回避するため、すべての手順が完了するまでワークロードを再デプロイしないでください。
  • 中断を計画する: ワークロードが一定期間中断される可能性があることを確認します。これらの手順は、主にホスト メンテナンスに必要な時間のため、完了までに数時間かかります。

すべてのノードの更新を同時に実行する

ホスト メンテナンスと、必要に応じて GKE バージョンのアップグレードを行うには、次の操作を行います。

  1. ワークロードを準備する: ワークロードを停止するか、最近のスナップショットまたはチェックポイントが作成されていることを確認します。
  2. ホスト メンテナンスを開始してモニタリングする:

    • グループ化されたメンテナンス スケジューリングを使用する予約のサブブロック: 対応する gcloud compute reservations サブコマンドを使用して、予約、予約ブロック、予約サブブロック全体でメンテナンスをトリガーします。たとえば、次のコマンドはサブブロックのメンテナンスを開始します。

      gcloud compute reservations sub-blocks perform-maintenance RESERVATION_NAME \
          --block-name=BLOCK_NAME \
          --sub-block-name=SUB_BLOCK_NAME \
          --zone=ZONE
      

      次のように置き換えます。

      • RESERVATION_NAME: 予約の名前。
      • BLOCK_NAME: 予約ブロックの名前。
      • SUB_BLOCK_NAME: 予約サブブロックの名前。
      • ZONE: 予約が存在するゾーン。

      Compute Engine は、サブブロック内のすべてのインスタンスのドレインと更新を同時に開始します。この処理には数時間かかることがあります。

      モニタリングするには、予約リソースの upcomingGroupMaintenance メタデータ フィールドをチェックして、メンテナンスの状態を確認します。詳細については、メンテナンス状態を表示するをご覧ください。

    • 独立したメンテナンス スケジューリングを使用するインスタンス: ノードプールのノードに cloud.google.com/perform-maintenance=true ラベルを適用して、オンデマンド インスタンスまたはサブブロックを使用しない予約のメンテナンスをトリガーします。

      kubectl label nodes -l cloud.google.com/gke-nodepool=NODE_POOL_NAME cloud.google.com/perform-maintenance=true --overwrite
      

      Compute Engine は、基盤となるインスタンスのドレインと更新を同時に開始します。この処理には数時間かかることがあります。詳細については、正常な終了のプロセスをご覧ください。

      メンテナンスのステータスをモニタリングするには、ノードを確認します。メンテナンスが完了すると、GKE はメンテナンス ラベルを削除します(適用されている場合)。メンテナンスが完了すると、Cloud Logging に次のメッセージを含むログが表示されます。

      Maintenance window has completed for this instance. All maintenance
      notifications on the instance have been removed.
      
  3. 省略可: GKE ノードのバージョンをアップグレードする。手順に沿ってノードの GKE バージョンをアップグレードします。

ローリング戦略を使用して推論ワークロードのノードを更新する

この戦略では、推論ワークロードを実行している GKE ノードのメンテナンスを手動で行う方法について説明します。これには、サービスの可用性を維持するためにノードをバッチで更新することが含まれます。この方法は、一定の割合のレプリカが一時的にオフラインになることを許容できるワークロードに最適です。

この戦略は、次の大まかな手順で行われます。

  1. ノードを特定してバッチ処理する: 更新するノードプールを選択します。ワークロードの障害耐性に応じて、ノードをバッチにグループ化します。
  2. バッチを反復処理する: バッチごとにメンテナンス ラベルを適用し、ラベルが削除されるまでノードのバッチをモニタリングします。
  3. GKE バージョンをアップグレードする: すべてのバッチでホスト メンテナンスが完了したら、GKE ノードのバージョンを変更します。

始める前の検討事項

始める前に、以下の注意事項を確認してください。

  • デプロイを理解する: 成功するには、ワークロードの分散、レプリカの配置、障害発生ドメインに関する詳細な知識が必要です。プロセス全体を通して、十分なサービング容量を維持してください。
  • バッチサイズを計画する: ノードをバッチで更新します。各バッチのサイズは、ワークロードのフォールト トレランスによって決まります。考慮すべき要素は次のとおりです。
    • サービング モデルあたりのレプリカ数。
    • ノードと障害発生ドメイン間でのレプリカの分散。
    • PodDisruptionBudgets を使用すると、同時に停止する Pod の最大数を適用できます。
    • 推奨事項: 管理を簡素化するには、異なるレプリカセットに異なるノードプールを割り当てることを検討してください。これにより、ノードプール レベルで障害発生ドメインを分離できます。
  • 時間制約を計算する: 次のタイミング要因を考慮します。
    • 各バッチでホスト メンテナンス ステップが完了するまでに数時間かかることがあります。
    • 必要な期限内にすべてのメンテナンスが完了するように、最小バッチサイズを計算します。
      1. MAINTENANCE_BLOCKS = floor(HOURS_TO_MAINTENANCE / 4)(HOURS_TO_MAINTENANCE は利用可能な合計時間)。
      2. MIN_PER_BATCH = TOTAL_NODE_COUNT / MAINTENANCE_BLOCKS
    • 選択するバッチサイズは MIN_PER_BATCH 以上にする必要があります。
  • 特定のワークロード タイプを確認する: それぞれの構成タイプについて、次の点を考慮してください。
    • Mixture of Experts(MOE): バッチ処理戦略で、各モデルに必要な最小レプリカ数が維持されるようにします。
    • 分離されたサービング: バッチを計画するときに、分離された設定に関係するすべてのレプリカを追跡します。
    • マルチホスト ノードプール(TPU、MNNVL): これらの構成では、一度にノードプール全体を停止することがあります。それに応じて、複数のノードプールにわたる障害発生ドメインを計画します。

ローリング アップデートをバッチで実施する

ローリング ホスト メンテナンス更新を実行するには、グループ化されたメンテナンス スケジューリングを使用する予約から、1 つ以上のサブブロックのバッチで容量を更新します。または、独立したメンテナンス スケジューリングを使用して、クラスタ内の特定のノードセットを名前で更新します。

リソースに適した戦略を選択します。

サブブロックのバッチで予約を更新する

サブブロックのバッチで容量予約のローリング ホスト メンテナンスを実行する手順は次のとおりです。

  1. メンテナンス用の予約を特定する: 容量予約名と、GKE クラスタで使用されている予約ブロックまたは予約サブブロックを特定します。これを行うには、GKE ノードラベルと gcloud compute reservations コマンドを使用して検索を行います。

    1. ノードプールのノードから、予約名と物理ブロックおよびサブブロックのトポロジ ID を一覧表示します。

      kubectl get nodes -l cloud.google.com/gke-nodepool=NODE_POOL_NAME \
          -o custom-columns='NAME:.metadata.name,RESERVATION:.metadata.labels.cloud\.google\.com/reservation-name,BLOCK_ID:.metadata.labels.cloud\.google\.com/gce-topology-block,SUBBLOCK_ID:.metadata.labels.cloud\.google\.com/gce-topology-subblock'
      

      NODE_POOL_NAME は、ノードプールの名前に置き換えます。

      出力値(予約名(nvidia-gb300-m7kp2xq9vd4j1 など)、ブロック ID(3f2a8c9b1d4e0756f8a2b3c1d9e4f0a5 など)、サブブロック ID(e7b91f4a3c2d58069e1a4b7f3d2c8056 など))をメモします。

    2. 予約ブロックのリソース名を特定するには、予約名を使用して Compute Engine 予約ブロックのリストをクエリし、ブロック ID でフィルタします。

      gcloud compute reservations blocks list RESERVATION_NAME \
          --zone=ZONE \
          --project=PROJECT_ID \
          --filter="physicalTopology.block=BLOCK_ID"
      

      次のように置き換えます。

      • RESERVATION_NAME: 予約の名前。
      • ZONE: 予約が存在するゾーン。
      • PROJECT_ID: 予約が存在するプロジェクト ID。
      • BLOCK_ID: ノードラベルから取得されたブロック ID。

      出力からブロックの名前を記録します。

    3. 予約サブブロックのリソース名を特定するには、予約名とブロック名を使用して予約サブブロックのリストをクエリし、サブブロック ID でフィルタします。

      gcloud compute reservations sub-blocks list RESERVATION_NAME \
          --block-name=BLOCK_NAME \
          --zone=ZONE \
          --project=PROJECT_ID \
          --filter="physicalTopology.subBlock=SUBBLOCK_ID"
      

      次のように置き換えます。

      • RESERVATION_NAME: 予約の名前。
      • BLOCK_NAME: 予約ブロック リソース名。
      • ZONE: 予約が存在するゾーン。
      • PROJECT_ID: 予約が存在するプロジェクト ID。
      • SUBBLOCK_ID: ノードラベルから取得したサブブロック ID。

      出力には、リソース名など、一致する予約サブブロックの詳細が表示されます。

  2. 予約をバッチに分割する: 特定された容量予約サブブロックを均等なバッチに分割します。前述の始める前の考慮事項セクションの時間制約を計算するリスト項目で説明されている式を使用して、バッチサイズを決定します。各バッチは 1 つ以上の予約サブブロックに対応し、各バッチは少なくともサブブロックのサイズである必要があります。

  3. ホスト メンテナンスを実行する: バッチごとに次の手順を完了します。

    1. 予約サブブロックのバッチを選択し、ホスト メンテナンスをトリガーします。予約、予約ブロック、予約サブブロック全体でメンテナンスをトリガーできます。A4X、A4X Max、TPU v6e、TPU7x などのマシンタイプでは、この方法でメンテナンスをトリガーする必要があります。メンテナンスはサブブロックのグループで実行されます。gcloud compute reservations sub-blocks perform-maintenance コマンドを使用します。

      gcloud compute reservations sub-blocks perform-maintenance RESERVATION_NAME \
          --block-name=BLOCK_NAME \
          --sub-block-name=SUB_BLOCK_NAME \
          --zone=ZONE
      

      次のように置き換えます。

      • RESERVATION_NAME: 予約の名前。
      • BLOCK_NAME: 予約ブロックの名前。
      • SUB_BLOCK_NAME: 予約サブブロックの名前。
      • ZONE: 予約が存在するゾーン。

      Compute Engine は、サブブロック内のすべてのインスタンスのドレインと更新を同時に開始します。この処理には数時間かかることがあります。

    2. メンテナンスのステータスをモニタリングするには、予約リソースの upcomingGroupMaintenance メタデータ フィールドをチェックして、メンテナンスの状態を確認します。詳細については、予約のメンテナンス状態を表示するをご覧ください。

    3. すべてのバッチのホスト メンテナンスが完了するまで、残りのバッチごとに前の手順を繰り返します。

  4. 省略可: GKE ノードのバージョンをアップグレードする。この手順は、すべての予約サブブロックのホスト メンテナンスが完了した後にのみ実行します。これにより、メンテナンスが完了していないホストに GKE ノードがデプロイされるシナリオを回避できます。ノードの GKE バージョンをアップグレードするの手順に沿って操作します。

ノードを一括更新する

サブブロックをバッチでサポートしていないオンデマンド インスタンスまたは予約に対してローリング ホスト メンテナンスを実行するには、次の操作を行います。

  1. メンテナンス対象のノードを特定する: メンテナンスを実行するすべてのノードを特定し、このリストを保存します。ノードを特定するには、次のいずれかの方法を使用するか、手動で選択します。

    • アクセラレータ(TPU または GPU)を使用するクラスタ内のすべてのノードを取得します。

      kubectl get nodes -o json | jq -r '.items[] | select(.spec.taints[]? | select(.key=="nvidia.com/gpu" or .key=="google.com/tpu")) | .metadata.name'
      
    • 特定のノードプール内のすべてのノードを取得します。

      kubectl get nodes -l cloud.google.com/gke-nodepool=NODE_POOL_NAME --no-headers -o custom-columns=":metadata.name"
      

      NODE_POOL_NAME は、ノードプールの名前に置き換えます。

    • 特定のラベルを持つすべてのノードを取得します。

      kubectl get nodes -l LABEL -o jsonpath='{.items[*].metadata.name}'
      

      LABEL は、ノードラベルに置き換えます。

  2. ノードをバッチに分割する: 特定されたノードを均等なバッチに分割します。前の始める前の考慮事項セクションの時間制約を計算するリスト項目で説明されている式を使用して、バッチサイズを決定します。

  3. ホスト メンテナンスを実行する: バッチごとに次の手順を完了します。

    1. ノードのバッチを選択し、メンテナンス ラベルを適用して、instances API を使用してインスタンス レイヤでメンテナンスをトリガーします。

      kubectl label nodes LIST_OF_NODES_IN_BATCH cloud.google.com/perform-maintenance=true --overwrite
      

      LIST_OF_NODES_IN_BATCH は、バッチのノードのスペース区切りリストに置き換えます。例: node-1 node-2 node-3

      Compute Engine は、基盤となるインスタンスのドレインと更新を同時に開始します。この処理には数時間かかることがあります。詳細については、正常な終了のプロセスをご覧ください。

    2. ホスト メンテナンスのステータスをモニタリングします。メンテナンスが完了すると、GKE はメンテナンス ラベルを削除します(適用されている場合)。メンテナンスが完了すると、Logging に次のメッセージを含むログが表示されます。

      Maintenance window has completed for this instance. All maintenance
      notifications on the instance have been removed.
      
    3. すべてのバッチのホスト メンテナンスが完了するまで、残りのバッチごとに前の手順を繰り返します。

  4. 省略可: GKE ノードのバージョンをアップグレードする。この手順は、すべてのノードのホスト メンテナンスが完了した後にのみ実行します。これにより、メンテナンスが完了していないホストに GKE ノードがデプロイされるシナリオを回避できます。ノードの GKE バージョンをアップグレードするの手順に沿って操作します。

ノードの GKE バージョンをアップグレードする

同時にアップグレードするノードの数を検討します。並列戦略では、ノードプール全体または複数のノードプールに対して同時にホスト メンテナンスを実行しました。ローリング戦略では、ホスト メンテナンスをバッチで実行しました。ノードのグループのサイズに基づいて、使用するアップグレード方法を決定します。

  • 並列戦略: ノードプールのゾーンあたりのノード数が 100 以下の場合は、サージ アップグレードを使用します。ノードプールのゾーンあたりのノード数が 100 を超える場合は、ノードプールを削除して再作成します。
  • ローリング戦略: バッチのノード数がゾーンごと、ノードプールごとに 100 個以下の場合は、サージ アップグレードを使用します。バッチのノード数がゾーンごと、ノードプールごとに 100 を超える場合は、ノードを削除して再作成します。

サージ アップグレードを使用する

  1. maxUnavailable 設定を使用してサージ アップグレードを構成し、ノードプール内で同時に使用不可にできるノードの数をゾーンごとに決定します。たとえば、ノードプールの 1 つのゾーンに 18 個のノードがある場合は、maxUnavailable フィールドの値を 18 に設定します。

    この設定は、余剰容量がない予約の容量を使用する場合に最適です。この設定を使用する理由については、リソースが制限された環境でのアップグレードをご覧ください。

  2. 次のコマンドを実行して、ノードプールをアップグレードします。複数のノードプールをアップグレードする場合は、ノードプールごとに次のコマンドを実行します。

    gcloud container clusters upgrade CLUSTER_NAME \
        --node-pool NODE_POOL_NAME \
        --cluster-version VERSION \
        --location CONTROL_PLANE_LOCATION \
        --quiet
    

    次のように置き換えます。

    • CLUSTER_NAME: クラスタの名前。
    • NODE_POOL_NAME: ノードプールの名前。
    • VERSION: ノードプールの推奨される自動アップグレード ターゲット。詳細については、Standard クラスタのノードプールのアップグレード情報を取得するをご覧ください。クラスタに推奨される自動アップグレード ターゲットがない場合は、GKE リリースノートの最新のバージョン アップデート エントリを確認してください。
    • CONTROL_PLANE_LOCATION: クラスタのコントロール プレーンのロケーション。

ノードを削除して再作成する

ノードプールを削除し、新しいバージョンを使用して再作成します。

  1. ノードプールを削除します。

    gcloud container node-pools delete NODE_POOL_NAME \
        --cluster CLUSTER_NAME \
        --location CONTROL_PLANE_LOCATION
    
  2. --cluster-version フラグを使用して新しいバージョンを渡し、ノードプールを再作成します。ノードプールに推奨される自動アップグレード ターゲットを渡します。詳細については、Standard クラスタのノードプールのアップグレード情報を取得するをご覧ください。クラスタに推奨される自動アップグレード ターゲットがない場合は、GKE リリースノートの最新のバージョン アップデート エントリを確認してください。