容量バッファを構成する

容量バッファは、Kubernetes の CapacityBuffer CustomResourceDefinition(CRD)を使用して、クラスタの予備容量と、事前にプロビジョニングされ、事前に構成された容量の一時停止状態をプロアクティブに管理することで、重要なワークロードの応答性と信頼性を向上させます。容量バッファを使用すると、クラスタ内で未使用のノード容量を一定量、明示的に定義できます。この予約容量により、Pod のスケジューリング時間を短縮できます。

優先度の高いワークロードを迅速にスケールアップする必要がある場合、新しいワークロードはノードのプロビジョニングを待つことなく、空き容量をすぐに使用できます。このアプローチにより、レイテンシが最小限に抑えられ、需要の急増時にリソースの競合を回避できます。

このページでは、固定レプリカ、リソース上限、割合ベースの容量バッファを構成する方法、特定のワークロードにバッファを専用にする方法、スタンバイ バッファの動作をカスタマイズする方法、コンテナ イメージをプリロードする方法について説明します。

始める前に

作業を始める前に、次のタスクが完了していることを確認してください。

  • Google Kubernetes Engine API を有効にする。
  • Google Kubernetes Engine API を有効化
  • このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化します。gcloud CLI をインストール済みの場合は、gcloud components update コマンドを実行して最新のバージョンを取得します。以前のバージョンの gcloud CLI では、このドキュメントのコマンドを実行できない場合があります。
  • バージョン 1.37.1-gke.3020000 以降を実行している GKE クラスタを作成するか、アクセスできるようにします。Autopilot クラスタのスタンバイ バッファには、カスタム ComputeClass が必要です。
  • Standard クラスタでノードプールの自動作成を有効にします。Autopilot クラスタでは、ノードプールの自動作成がすでに有効になっています。ノードプールの自動作成は、アクティブ バッファでは省略可能ですが、推奨されます。スタンバイ バッファでは必須です。

前提条件となる Kubernetes オブジェクトを作成する

CapacityBuffer を構成するには、必要なすべてのオブジェクト(CapacityBuffer 自体、PodTemplate やワークロードなどの追加リソース)を保持する Namespace が必要です。PodTemplate と CapacityBuffer は同じ Namespace に存在する必要があります。Namespace を作成することも、default Namespace などの既存の Namespace を使用することもできます。

構成する CapacityBuffer のタイプに応じて、次のいずれかも必要です。

  • PodTemplate: バッファ容量の 1 ユニットに対するリソース要件を定義します。CapacityBuffer オブジェクトで指定された構成は、Pod テンプレートを参照します。
  • ワークロード: CapacityBuffer オブジェクトで参照する既存のワークロード。このガイドでは、ワークロードの例として Deployment オブジェクトを使用しますが、容量バッファは次のいずれかのリソースタイプをサポートしています。

    • デプロイ
    • ReplicaSet
    • StatefulSet
    • ReplicationController
    • ジョブ
    • scale サブリソースを実装する CustomResourceDefinition(CRD)。

このセクションでは、これらのオブジェクトの例を示します。容量バッファを使用して構成するワークロードがすでにある場合は、容量バッファを適用するに進みます。

Kubernetes ワークロードの例を作成するには、次の操作を行います。

  1. 次のマニフェストを namespace.yaml として保存します。

    apiVersion: v1
    kind: Namespace
    metadata:
      name: capacity-buffer-example
      labels:
        name: capacity-buffer-example
    

    このマニフェストは、capacity-buffer-example という名前空間を作成します。

  2. 省略可: カスタム ComputeClass で容量バッファを使用するには、次のマニフェストを custom-compute-class.yaml として保存します。

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: ccc-example
    spec:
      # Buffers are also created according to these priorities
      priorities:
      - machineFamily: n4
      - machineFamily: n4d
      - machineFamily: c4
      - machineFamily: c4d
      nodePoolAutoCreation:
        enabled: true
    

    このマニフェストは、GKE がプロビジョニングするノードのコンピューティング優先度を定義して制御するカスタム ComputeClass を作成します。詳細については、カスタム ComputeClass をご覧ください。

  3. 次のマニフェストを buffer-pod-template.yaml として保存します。

    apiVersion: v1
    kind: PodTemplate
    metadata:
      name: buffer-unit-template
      namespace: capacity-buffer-example # the namespace must be the same namespace as the CapacityBuffer
    template:
      spec:
        terminationGracePeriodSeconds: 0
        containers:
        - name: buffer-container
          image: registry.k8s.io/pause:3.9
          resources:
            requests:
              cpu: "1"
              memory: "1Gi"
            limits:
              cpu: "1"
              memory: "1Gi"
        # Optional: Using buffers with a custom ComputeClass /
        # controls the properties of the provisioned nodes.
        nodeSelector:
          cloud.google.com/compute-class: ccc-example
    

    このマニフェストは、バッファ容量の 1 ユニット(1 CPU と 1Gi メモリ)のリソース要件を定義する PodTemplate を作成します。この構成では、GKE がバッファにプロビジョニングする容量ユニットのサイズを指定します。たとえば、この PodTemplate を使用すると、クラスタがスケールアップした場合、GKE は 1 つ未満の CPU と 1 Gi の使用可能なリソースを持つノードをバッファの一部として考慮しません。

  4. 次のマニフェストを sample-workload-deployment.yaml として保存します。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: critical-workload-ref
      namespace: capacity-buffer-example # the namespace must be the same namespace as the CapacityBuffer
    spec:
      replicas: 10
      selector:
        matchLabels:
          app: critical-workload
      template:
        metadata:
          labels:
            app: critical-workload
        spec:
          containers:
          - name: busybox
            image: busybox
            command: ["sleep", "3600"]
            resources:
              requests:
                cpu: 100m
          # Optional: Using buffers with a custom ComputeClass /
          # controls the properties of the provisioned nodes.
          nodeSelector:
            cloud.google.com/compute-class: ccc-example
    

    このマニフェストは、10 個のレプリカを含む Deployment のサンプルを作成します。これは、次のセクションの割合ベースのバッファの例の参照オブジェクトです。

  5. マニフェストをクラスタに適用します。

    kubectl apply -f namespace.yaml -f custom-compute-class.yaml -f buffer-pod-template.yaml -f sample-workload-deployment.yaml
    
  6. GKE がオブジェクトを作成したことを確認します。

    kubectl get podtemplate -n capacity-buffer-example
    kubectl get deployment critical-workload-ref -n capacity-buffer-example
    

    出力は次のようになります。

    NAME                   AGE
    buffer-unit-template   1m
    
    NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
    critical-workload-ref   10/10   10           10          1m
    

容量バッファを適用する

このセクションでは、ワークロードに適用できるさまざまなタイプの容量バッファの例を示します。

固定レプリカ バッファを構成する

固定レプリカを使用して CapacityBuffer を構成すると、PodTemplate に基づいて必要なバッファユニットの正確な数を指定できます。

固定レプリカを含むバッファを作成するには、次の手順を行います。

  1. 次のマニフェストを cb-fixed-replicas.yaml として保存します。

    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: CapacityBuffer
    metadata:
      name: fixed-replica-buffer
      namespace: NAMESPACE
    spec:
      podTemplateRef:
        name: POD_TEMPLATE
      replicas: 3
      provisioningStrategy: "STRATEGY"
    

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

    • NAMESPACE: Namespace の名前(例: capacity-buffer-example)。
    • POD_TEMPLATE: リソース要件を定義する PodTemplate(例: buffer-unit-template)。
    • STRATEGY: プロビジョニング戦略("buffer.x-k8s.io/active-capacity"(デフォルト)または "buffer.gke.io/standby-capacity")。

    このマニフェストは、PodTemplate を参照する CapacityBuffer リソースを作成し、特定の数のバッファ ユニットをリクエストします。

  2. 次のようにマニフェストを適用します。

    kubectl apply -f cb-fixed-replicas.yaml
    
  3. GKE が容量バッファを適用したことを確認します。

    kubectl get capacitybuffer fixed-replica-buffer -n NAMESPACE
    

    ステータスの replicas フィールドには、マニフェストで定義したレプリカの数を反映した 3 が表示されます。STATUS フィールドに ReadyForProvisioning が表示されます。

リソース上限バッファを構成する

limits フィールドを使用すると、バッファが消費するリソースの最大量を定義できます。この量は、PodTemplate のサイズに基づいて計算されます。

リソース上限バッファを作成する手順は次のとおりです。

  1. 次のマニフェストを cb-resource-limits.yaml として保存します。

    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: CapacityBuffer
    metadata:
      name: resource-limit-buffer
      namespace: NAMESPACE
    spec:
      podTemplateRef:
        name: POD_TEMPLATE
      limits:
        cpu: "5"
        memory: "5Gi"
      provisioningStrategy: "STRATEGY"
    

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

    • NAMESPACE: Namespace の名前(例: capacity-buffer-example)。
    • POD_TEMPLATE: リソース要件を定義する PodTemplate(例: buffer-unit-template)。
    • STRATEGY: プロビジョニング戦略("buffer.x-k8s.io/active-capacity"(デフォルト)または "buffer.gke.io/standby-capacity")。

    このマニフェストは、合計上限が 5 個の CPU と 5 GiB のメモリである CapacityBuffer リソースを作成します。前の手順の PodTemplate の例を使用している場合は、各ユニットを 1 CPU と 1Gi メモリとして定義します。これにより、5 つのバッファ ユニットが作成されます。

  2. 次のようにマニフェストを適用します。

    kubectl apply -f cb-resource-limits.yaml
    
  3. GKE が容量バッファを適用したことを確認します。

    kubectl get capacitybuffer resource-limit-buffer -n NAMESPACE
    

    CapacityBuffer のステータスを確認します。replicas フィールドには、定義した上限から導出された値が表示されます。前のセクションの PodTemplate の例を使用している場合は、5 バッファ ユニットが表示されます。これは、定義された上限内に収まるユニットの最大数です。

割合ベースのバッファを構成する

割合ベースのバッファを構成すると、既存のスケーラブルなワークロードの割合に基づいてバッファのサイズが動的に設定されます。割合ベースの容量バッファは、スケール サブリソースを実装する Kubernetes スケーラブル オブジェクト(Deployment、StatefulSet、ReplicaSet、Job など)でのみサポートされます。Pod テンプレートには replicas フィールドがないため、Pod テンプレートに割合ベースのバッファを定義することはできません。

ほとんどの場合、割合ベースのバッファではなく、固定レプリカまたはリソース上限戦略から始めます。どちらを使用するか決める際は、次の点を考慮してください。

  • ワークロードが低い数またはゼロにスケーリングされる場合、安全マージンがアクティブな Pod に比例して減少するため、割合ベースのバッファは急激なスケールアップに対応しにくくなります。
  • スタンバイ ノードは、一時停止前の初期化期間中にコンピューティング料金が発生します。ワークロードの変動に合わせてスタンバイ バッファを動的にスケーリングすると、コンピューティング リソースが無駄になります。代わりに、スタンバイ バッファに固定レプリカまたはリソース上限を使用してください。
  • 割合ベースのバッファは、レプリカ数が少ない場合にスケールしない大規模なデプロイのアクティブ バッファに主に役立ちます。

参照されるワークロードがスケールダウンしたときに最小バッファサイズを維持するには、replicas フィールドと percentage フィールドを一緒に設定します。GKE は、より多くのバッファ ユニットを生成するフィールドを使用します。バッファサイズの上限を設定するには、limits フィールドも設定します。

たとえば、10 個のレプリカを持つ Deployment を参照する percentage: 20 と replicas: 3 を含むバッファについて考えてみましょう。10 個のレプリカの 20% は 2 で、replicas の値 3 よりも小さいため、GKE は 3 個のバッファ ユニットをプロビジョニングします。Deployment が 20 個のレプリカにスケールされると、バッファは 4 ユニットに増加します。詳細については、CapacityBuffer のリファレンス ドキュメントをご覧ください。

割合ベースのバッファを作成する手順は次のとおりです。

  1. 次のマニフェストを cb-percentage-based.yaml として保存します。

    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: CapacityBuffer
    metadata:
      name: percentage-buffer
      namespace: NAMESPACE
    spec:
      scalableRef:
        apiGroup: apps
        kind: Deployment
        name: SCALABLE_RESOURCE_NAME
      percentage: 20
      provisioningStrategy: "STRATEGY"
    

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

    • NAMESPACE: 名前空間の名前。
    • SCALABLE_RESOURCE_NAME: スケーラブルなリソースの名前(例: critical-workload-ref)。
    • STRATEGY: プロビジョニング戦略("buffer.x-k8s.io/active-capacity"(デフォルト)または "buffer.gke.io/standby-capacity")。

    このマニフェストは、参照先リソースのレプリカの 20% に相当するバッファサイズをリクエストする CapacityBuffer リソースを作成します。前のセクションの Deployment の例を使用している場合、レプリカの値は 10 に設定されます。

  2. 次のようにマニフェストを適用します。

    kubectl apply -f cb-percentage-based.yaml
    
  3. GKE が容量バッファを適用したことを確認します。

    kubectl get capacitybuffer percentage-buffer -n NAMESPACE
    

    CapacityBuffer のステータスを確認します。replicas フィールドには、割合の計算結果の値が表示されます。前のセクションの Deployment の例を使用している場合は、2 バッファ ユニットが表示されます。これは、Deployment で定義された 10 個のレプリカの 20% です。

  4. Deployment を 20 個のレプリカに手動でスケールアップして、動的スケーリングをテストします。

    kubectl scale deployment critical-workload-ref -n NAMESPACE --replicas=20
    

    CapacityBuffer コントローラが反応し、バッファを 4 つのレプリカに自動スケーリングします。

特定のワークロードに容量バッファを専用にする

デフォルトでは、バッファノードのスケジューリング制約に一致する保留中の Pod は、バッファ容量を要求できます。複数のワークロードがカスタム ComputeClass またはノードプールを共有する場合は、ワークロードの分離を使用して、特定のワークロードの容量バッファを予約します。このアプローチでは、ノードプールの自動作成、または Standard クラスタのアクティブ バッファ用の専用ノードプールが必要です。

多数の個々のワークロードに個別の容量バッファを割り当てないでください。専用バッファごとに独自のノードプールが必要になるため、バッファのプロビジョニングと補充にかかる時間が長くなります。推奨されるバッファ数については、スケーラビリティをご覧ください。

容量バッファを特定のワークロード専用にするには、次の操作を行います。

  1. ワークロード マニフェスト(前提条件となる Kubernetes オブジェクトを作成するの sample-workload-deployment.yaml など)で、Pod 仕様にカスタム toleration とノードセレクタを追加します。

    spec:
      tolerations:
      - key: KEY
        operator: Equal
        value: "VALUE"
        effect: NoSchedule
      nodeSelector:
        KEY: "VALUE"
        cloud.google.com/compute-class: ccc-example
    

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

    • KEY: taint とノードラベルのカスタムキー(group など)。制限付きのキー接頭辞については、ワークロードの分離の制限事項をご覧ください。
    • VALUE: ワークロードを識別するカスタム値(critical-workload など)。

    Autopilot クラスタでは、バッファがサポートされていない Pod ベースの課金モデルではなく、ノードベースの課金を使用するように、nodeSelector フィールドにカスタム ComputeClass またはハードウェア セレクタを保持します。

  2. 同じスケジューリング制約を使用するように CapacityBuffer を構成します。

    • CapacityBuffer で scalableRef フィールドを使用する場合は、spec.scalableRef フィールドでワークロードを参照します。バッファは、ワークロードの tolerations フィールドと nodeSelector フィールドを自動的に継承します。
    • CapacityBuffer で podTemplateRef フィールドを使用する場合は、同じ tolerations フィールドと nodeSelector フィールド(buffer-pod-template.yaml など)を PodTemplate マニフェストに追加します。
  3. マニフェストを適用して CapacityBuffer を作成します。手順については、容量バッファを適用するをご覧ください。スタンバイ バッファにイメージをプリロードする場合は、プリロード DaemonSet にカスタム toleration を追加して、専用バッファノードでスケジュールできるようにします。バッファがカスタム ComputeClass を使用している場合、DaemonSet には ComputeClass taint の toleration も必要です。

    tolerations:
    - key: "buffer.gke.io/standby-capacity-node-suspended"
      operator: "Exists"
    - key: KEY
      operator: Equal
      value: "VALUE"
      effect: NoSchedule
    - key: cloud.google.com/compute-class
      operator: Equal
      value: ccc-example
      effect: NoSchedule
    
  4. クラスタ オートスケーラーがバッファノードをプロビジョニングしたら、ノードに専用のノードラベルとノード taint があることを確認します。

    kubectl get nodes -l KEY=VALUE \
        -o custom-columns='NAME:.metadata.name,TAINTS:.spec.taints[*].key'
    

    出力の各ノードには、KEY taint キーが一覧表示されます。バッファがカスタム ComputeClass を使用している場合、ノードには cloud.google.com/compute-class taint キーも表示されます。スタンバイ バッファノードには、GKE が管理する taint(一時停止中のノードの buffer.gke.io/standby-capacity-node-suspended など)もあります。ワークロードがスケールアップしたら、kubectl get pods -n NAMESPACE -o wide を実行し、NODE 列にこの出力の専用ノード名が表示されていることを確認します。

スタンバイ バッファの動作をカスタマイズする

アノテーションを使用して、スタンバイ バッファの起動方法と更新方法をカスタマイズできます。CapacityBuffer リソースの metadata.annotations フィールドに次のアノテーションを追加します。

  • buffer.gke.io/standby-capacity-init-time: ノードが作成されてから GKE が一時停止するまでのアクティブな時間。5m や 1h などの期間文字列を指定します。デフォルトは 5m です。
  • buffer.gke.io/standby-capacity-refresh-frequency: GKE が一時停止中のノードを更新する頻度。12h や 24h などの期間文字列を最大 120h(5 日間)まで指定します。デフォルトは 24h です。

次の例は、スタンバイ バッファの動作をカスタマイズするためのオプション フィールドを含むマニフェストを示しています。

apiVersion: autoscaling.x-k8s.io/v1beta1
kind: CapacityBuffer
metadata:
  name: customized-standby-buffer
  namespace: my-namespace
  annotations:
    buffer.gke.io/standby-capacity-init-time: "15m"
    buffer.gke.io/standby-capacity-refresh-frequency: "12h"
spec:
  podTemplateRef:
    name: buffer-unit-template
  replicas: 3
  provisioningStrategy: "buffer.gke.io/standby-capacity"

スタンバイ バッファに画像をプリロードする

スタンバイ ノードが再開したときにワークロードの起動時間を短縮するには、DaemonSet を使用してコンテナ イメージをプリロードします。DaemonSet は、ノードが一時停止される前の起動期間中に実行されます。

DaemonSet を使用してイメージをプリロードするには、次の手順を完了します。

  1. 次のマニフェストを image-puller-daemonset.yaml として保存します。

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: image-prefetch-daemonset
      namespace: NAMESPACE
    spec:
      selector:
        matchLabels:
          name: image-prefetch
      template:
        metadata:
          labels:
            name: image-prefetch
        spec:
          tolerations:
          - key: "buffer.gke.io/standby-capacity-node-suspended"
            operator: "Exists"
          initContainers:
          - name: image-puller
            image: IMAGE_NAME
            command: ["sh", "-c", "true"]
          containers:
          - name: pause
            image: registry.k8s.io/pause:3.9
    

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

    • NAMESPACE: DaemonSet の Namespace(例: capacity-buffer-example)。
    • IMAGE_NAME: プリロードするイメージの名前(例: your-app-image:latest)。

    このマニフェストには buffer.gke.io/standby-capacity-node-suspended toleration が含まれているため、GKE がスタンバイ ノードを一時停止した後も、DaemonSet はスタンバイ ノードにスケジュールされたままになります。

  2. DaemonSet マニフェストをクラスタに適用します。

    kubectl apply -f image-puller-daemonset.yaml
    
  3. DaemonSet が作成されていることを確認します。

    kubectl get daemonset image-prefetch-daemonset -n NAMESPACE
    
  4. 容量バッファが作成され、プロビジョニングの準備ができていることを確認します。

    kubectl get capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE
    

    ステータスを確認します。STATUS フィールドに ReadyForProvisioning が表示されます。

容量バッファのステータスとパフォーマンスをモニタリングする

容量バッファのステータスと健全性は、kubectl コマンドと Cloud Monitoring の指標を使用してモニタリングできます。

CapacityBuffer リソースのステータスを確認する

容量バッファの状態を確認し、ワークロードを受信する準備ができていることを確認するには、次の手順を完了します。

  1. クラスタ全体のすべての容量バッファのステータスを取得します。

    kubectl get capacitybuffer -A
    
  2. 特定のバッファの詳細なステータス、条件、イベントログを検査します。

    kubectl describe capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE
    

一時停止中のスタンバイ バッファノードを特定する

スタンバイ バッファ VM は事前にプロビジョニングされますが、費用を削減するために一時停止状態に保たれます。これらの停止中のノードは、カスタム条件があるため識別できます。一時停止したノード インスタンスを監査するには、次のコマンドを実行します。

kubectl get nodes -o custom-columns='NAME:.metadata.name,SUSPENDED:.status.conditions[?(@.type=="Suspended")].status'

True のステータスは、スタンバイ VM が一時停止していることを示します。ステータスが False または <none> の場合は、ノードがアクティブで実行中であることを示します。

Cloud Monitoring を使用したパフォーマンスのモニタリング

容量バッファがスケールアップ時間に及ぼすエンドツーエンドの影響をモニタリングするには、 Google Cloud コンソールの [起動レイテンシ] ダッシュボードを使用します。[Pod の起動レイテンシの分布] グラフと [Pod の最初の準備完了までのレイテンシ] グラフを使用して、Pod の作成から準備完了までの kubernetes.io/pod/latencies/pod_first_ready 指標を追跡します。Cloud Logging で Scheduled イベントをクエリして、Pod のスケジューリング レイテンシを測定することもできます。手順については、起動レイテンシ指標をモニタリングするをご覧ください。

容量バッファを削除する

ワークロードに容量バッファが不要になった場合は、CapacityBuffer オブジェクトを削除します。これにより、プレースホルダ Pod が削除され、クラスタ オートスケーラーがノードをスケールダウンできるようになります。

kubectl delete capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE

CAPACITY_BUFFER_NAME は、削除する CapacityBuffer の名前に置き換えます。

トラブルシューティング

次のセクションでは、容量バッファに関する一般的な問題の解決方法について説明します。

課金モデルが原因で容量バッファの準備ができていない

Pod ベースの課金モデル(Pod ごとの課金)を使用するワークロードに CapacityBuffer を作成すると、容量バッファはプロビジョニングの準備が整いません。

この問題を特定するには、CapacityBuffer のステータスを確認します。

kubectl describe capacitybuffer BUFFER_NAME -n NAMESPACE

タイプが ReadyForProvisioning で、ステータスが False の条件を探します。

この問題を解決するには、CapacityBuffer がノードベースの課金に対応しているワークロードまたは PodTemplate を参照していることを確認します。

カスタム ComputeClass によってプロビジョニングされたノードでバッファ Pod がスケジュールされない

CapacityBuffer 構成の依存関係(PodTemplate など)でカスタム ComputeClass が選択されている場合、新しくプロビジョニングされたノードにバッファ Pod がスケジュールされないという問題が発生することがあります。この問題により、クラスタ オートスケーラーは、アイドル状態のノードが削除されている間に、冗長なノードプールとノードを繰り返し作成します。

この問題は、カスタム ComputeClass が taint または特定のランタイム要件を持つノードをプロビジョニングし、バッファ Pod(またはバッファ Pod が依存する PodTemplate)に一致する toleration または設定がない場合に発生します。

この問題を解決するには、必要な toleration、ノードセレクタ、またはランタイム クラスを指定するように CapacityBuffer 構成を更新します。たとえば、依存関係が GKE Sandbox で構成されたカスタム ComputeClass を選択している場合は、依存関係を更新して次のいずれかを行います。

  • spec.runtimeClassName: gvisor フィールドを指定します。
  • sandbox.gke.io/runtime=gvisor:NoSchedule taint の明示的な toleration を含めます。

詳細については、カスタム ComputeClass のドキュメントをご覧ください。

スタンバイ バッファノードを再開できない

一時停止中のスタンバイ バッファノードが再開されない理由としては、次のいずれかが考えられます。

  • 一時停止したスタンバイ ノードを再開するには、ノードのマシンタイプと特定の CPU プラットフォーム世代(E2 マシンシリーズや N2 マシンシリーズなど)のゾーンで、使用可能な Compute Engine の容量が必要です。ゾーンにその構成に十分なコンピューティング容量がない場合、ノードは再開できません。詳細については、Compute Engine の一時停止と再開の制限事項をご覧ください。
  • カスタム ComputeClass で優先度の高いノードへのアクティブな移行(activeMigration.optimizeRulePriority: true)が有効になっており、Spot VM がオンデマンド VM よりも高い優先度に設定されている場合、GKE はオンデマンド スタンバイ ノードを Spot VM に移行します。Spot VM は容量の制約を受けやすく、一時停止された Spot VM は再開時にオンデマンド VM に変換できないため、これらの制約により、スタンバイ ノードが再開できなくなる可能性があります。
  • ノードを再開すると、プロジェクトの Compute Engine の割り当てを超過します。詳細については、割り当て上限が原因で容量バッファをプロビジョニングできないをご覧ください。

スタンバイ ノードが再開できなかった理由を特定するには、ログ エクスプローラで Compute Engine 監査ログをクエリして、compute.instances.resume オペレーションの ZONE_RESOURCE_POOL_EXHAUSTED エラーまたは QUOTA_EXCEEDED エラーを確認します。

この問題を解決または軽減するには、次のいずれかを行います。

  • リージョン クラスタを使用して、クラスタ オートスケーラーが複数のゾーンにノードをプロビジョニングまたは再開できるようにします。
  • カスタム ComputeClass の spec.priorities リストで複数のマシン ファミリーを構成します。一時停止したノードを再開できない場合、クラスタ オートスケーラーは、別の優先度ルールに基づいて新しいノードの作成にフォールバックできます。これらの新しいノードは、再開されたスタンバイ ノードよりも準備に時間がかかります。一時停止中のノードは元のマシンタイプでのみ再開できるため、この構成では一時停止中のノードを再開できません。
  • オンデマンド VM で専用のカスタム ComputeClass を使用するか、スタンバイ バッファが使用する ComputeClass の activeMigration.optimizeRulePriority フィールドを false に設定します。
  • スタンバイ バッファを小さなアクティブ バッファと組み合わせて、トラフィックの急増を吸収します。

割り当て上限に達したため、容量バッファをプロビジョニングできない

容量バッファが Kubernetes ResourceQuotas または Compute Engine の割り当てを超えると、リクエストされたレプリカ数よりも少ないレプリカがプロビジョニングされるか、スケールアップに失敗する可能性があります。

バッファを制限している割り当てを特定するには、次の割り当てを 1 つ以上確認します。

  • Namespace の Kubernetes ResourceQuota がバッファを制限しているかどうかを確認します。

    kubectl describe capacitybuffer \
        CAPACITY_BUFFER_NAME \
        -n NAMESPACE
    

    status.conditions の出力で、ステータスが True の LimitedByQuotas 条件を探します。アクティブ バッファ ユニットとスタンバイ バッファ ユニットの両方(一時停止中のスタンバイ ノードをバックアップするユニットを含む)は、バッファ Pod が実行されているかのように、Namespace の ResourceQuota の上限にカウントされます。バッファが Namespace の割り当てを超えると、GKE は status.replicas フィールドを上限に設定して、使用可能な割り当て内に収まるようにします。

  • Compute Engine プロジェクトの割り当てがノードのプロビジョニングをブロックしているかどうかを確認します。ログ エクスプローラで、container.googleapis.com/cluster-autoscaler-visibility ログで no.scale.up.nap.quota.exceeded イベントを検索するか、Compute Engine 監査ログで QUOTA_EXCEEDED エラーを検索します。

    スタンバイ バッファの Compute Engine 割り当てを確認するときは、vCPU とメモリの割り当てに加えて、次の両方の割り当てを確認します。

    • 一時停止したスタンバイ ノードは内部 IP アドレスと外部 IP アドレスを保持するため、使用中の IP アドレスの割り当てが消費されます。
    • スタンバイ VM を一時停止すると、Compute Engine はノードのメモリをディスクに書き込みます。これにより、ノードのメモリサイズに比例して Persistent disk standard (GB) ディスク割り当てが消費されます。

割り当て上限を解決するには、次のいずれかを行います。

スタンバイ ノードが再開すると、DaemonSet Pod がデータを受信しなくなる

一時停止したスタンバイ バッファノードが再開すると、そのノードの DaemonSet Pod は、ノードが一時停止する前に開かれた長時間接続を介してデータを受信できなくなる可能性があります。Pod はエラーをログに記録せず、再接続もしません。

この問題は、DaemonSet Pod が受信専用クライアントとして機能する場合に発生します。たとえば、ストリーミング HTTP レスポンス、WebSocket 接続、サーバー送信イベント、gRPC サーバー ストリーミング呼び出しなどです。スタンバイ ノードが一時停止している間に、サーバーまたは中間ネットワーク デバイスがタイムアウトし、接続が閉じられます。ノードが再開すると、Pod のネットワーク スタックは接続が開いていると見なします。Pod はデータを送信しないため、接続が閉じられたことを検出せず、データを無期限に待機します。

この問題を解決するには、次のいずれかを行って、クローズされた接続を検出し、再接続するように DaemonSet Pod のクライアント アプリケーションを構成します。

  • Pod のアプリケーションでクライアントサイドの TCP キープアライブを構成します(サーバーでのみキープアライブを有効にしても、Pod には通知されません)。TCP キープアライブ パラメータの詳細については、アイドル接続をご覧ください。
    1. クライアント ライブラリまたは言語ランタイム(Node.js の socket.setKeepAlive(true, initialDelay) や Go の net.Dialer.KeepAlive など)で SO_KEEPALIVE ソケット オプションを有効にします。一部のランタイムでは、TCP キープアライブがデフォルトで無効になっています。
    2. オペレーティング システムのデフォルトに依存するのではなく、数秒などの短いキープアライブ アイドル時間(TCP_KEEPIDLE)を構成します。
    3. キープアライブ プローブが失敗したときに接続エラー(接続リセットやタイムアウトなど)をキャッチし、新しい接続を開くようにアプリケーションを更新します。
  • クライアントでアプリケーション レベルのハートビートまたは読み取りタイムアウト(WebSocket の ping フレームと pong フレーム、gRPC キープアライブ ping など)を構成し、タイムアウトが発生したときに再接続するようにアプリケーションを更新します。

次のステップ