プリエンプティブル VM を使用してフォールト トレラント ワークロードを実行する


このページでは、Google Kubernetes Engine(GKE)でプリエンプティブル VM を使用する方法について説明します。

概要

プリエンプティブル VM は、標準 VM よりも低価格で、可用性が保証されない Compute Engine VM インスタンスです。プリエンプティブル VM は、Spot VM と同様の機能を備えていますが、作成後 24 時間しか持続しません。

場合によっては、プリエンプティブル VM が 24 時間以上続くことがあります。これは、新しい Compute Engine インスタンスの起動が極度に高速であるため、別の Compute Engine VM が作成されたことを Kubernetes が認識できない場合に発生する可能性があります。基盤となる Compute Engine インスタンスの最大持続時間は 24 時間であり、想定されるプリエンプティブル VM の動作に従います。

Spot VM との比較

プリエンプティブル VM には、次のような Spot VM との多くの類似点があります。

最大有効期限がない Spot VM とは異なり、プリエンプティブル VM は作成後最大 24 時間しか持続しません。

新しいクラスタとノードプールでプリエンプティブル VM を有効にして、nodeSelector またはノード アフィニティを使用してスケジューリングを制御できます。また、ノードがプリエンプトされたときのシステム ワークロードの問題を回避するために、taint と toleration を使用できます。

プリエンプティブル VM の終了と正常なシャットダウン

Compute Engine がプリエンプティブル VM によって使用されたリソースを再利用する必要がある場合、プリエンプション通知が GKE に送信されます。プリエンプティブル VM は、終了通知を受け取ってから 30 秒後に終了します。

デフォルトでは、クラスタはノードのグレースフル シャットダウンを使用します。kubelet は終了通知を認識し、ノードで実行中の Pod を正常に終了します。Pod が Deployment の一部である場合、コントローラは新しい Pod を作成してスケジューリングし、終了した Pod を置き換えます。

kubelet では、システム以外の Pod が正常に終了するためにベストエフォート方式で 15 秒の猶予が与えられます。その後、システム Pod(priorityClasses が system-cluster-critical または system-node-critical の Pod)が正常に終了するために 15 秒の猶予があります。

ノードの正常な終了中に、kubelet が Pod のステータスを更新し、終了する Pod に Failed フェーズと Terminated の理由を割り当てます。

終了した Pod 数が、100 ノード未満のクラスタの場合は 1,000、100 ノード以上のクラスタの場合は 5,000 のしきい値に達すると、ガベージ コレクションによって Pod がクリーンアップされます。

次のコマンドを使用して、終了した Pod を手動で削除することもできます。

  kubectl get pods --all-namespaces | grep -i NodeShutdown | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n
  kubectl get pods --all-namespaces | grep -i Terminated | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n

Kubernetes の動作の変更

GKE でプリエンプティブル VM を使用すると、Kubernetes によって提供される次のような保証と制約が変更されます。

  • Compute Engine からプリエンプション通知を受け取ってから 30 秒後に、GKE は Pod の猶予期間なしでプリエンプティブル VM をシャットダウンします。

  • プリエンプティブル VM の再利用は自発的なものではなく、PodDisruptionBudgets の保証の対象外です。構成した PodDisruptionBudget 以上に可用性が低くなる場合があります。

制限事項

プリエンプティブル VM を含むクラスタまたはノードプールを作成する

Google Cloud CLI を使用して、プリエンプティブル VM を含むクラスタまたはノードプールを作成できます。

プリエンプティブル VM を含むクラスタを作成するには、次のコマンドを実行します。

gcloud container clusters create CLUSTER_NAME \
    --preemptible

CLUSTER_NAME は、使用するクラスタの名前に置き換えます。

プリエンプティブル VM を持つノードプールを作成するには、次のコマンドを実行します。

gcloud container node-pools create POOL_NAME \
    --cluster=CLUSTER_NAME \
    --preemptible

POOL_NAME は、新しいノードプールの名前に置き換えます。

nodeSelector を使用してプリエンプティブル VM 上で Pod をスケジューリングする

GKE は、プリエンプティブル VM を使用するノードに、cloud.google.com/gke-preemptible=truecloud.google.com/gke-provisioning=preemptible(GKE バージョン 1.25.5-gke.2500 以降を実行しているノードの場合)のラベルを追加します。Deployment で nodeSelector を使用して、Pod をプリエンプティブル VM 上にスケジューリングするよう GKE に指示できます。

たとえば、次の Deployment は、cloud.google.com/gke-preemptible ラベルを使用してプリエンプティブル VM をフィルタします。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-app
  template:
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
      - name: hello-app
        image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
        resources:
          requests:
            cpu: 200m
      nodeSelector:
        cloud.google.com/gke-preemptible: "true"

プリエンプティブル VM に Node Taints を使用する

プリエンプティブル VM を使用するノードを taint することで、対応する容認機能を備えた Pod のみが GKE によってそうしたノードに配置されるようにできます。

プリエンプティブル VM を使用するノードプールに Node Taint を追加するには、次のコマンドのように、ノードプール作成時に --node-taints フラグを使用します。

gcloud container node-pools create POOL2_NAME \
    --cluster=CLUSTER_NAME \
    --node-taints=cloud.google.com/gke-preemptible="true":NoSchedule

これで、Node taint を許容する Pod だけが、このノードにスケジュールされるようになります。

関連する容認機能を Pod に追加するには、デプロイを変更して、次の記述を Pod 仕様に追加します。

tolerations:
- key: cloud.google.com/gke-preemptible
  operator: Equal
  value: "true"
  effect: NoSchedule

GPU プリエンプティブル VM の Node Taints

プリエンプティブル VM では、GPU の使用がサポートされています。プリエンプティブル VM を使用する GPU ノードプールを追加する前に、クラスタには、プリエンプティブル VM を使用しない他のノードプールを 1 つ以上作成する必要があります。標準ノードプールがあることで、GKE は DNS などのシステム コンポーネントを安全に配置できます。

プリエンプティブル VM を使用する GPU ノードプールがある新しいクラスタを作成する場合、またはプリエンプティブル VM を使用する新しい GPU ノードプールを標準ノードプールがまだ備わっていないクラスタに追加する場合、GKE によって nvidia.com/gpu=present:NoSchedule taint がノードに自動的に追加されることはありません。システム Pod が、GKE によってプリエンプティブル VM にスケジューリングされことはあります。この場合は、中断が発生する可能性があります。GPU ノードは、非 GPU ノードより高コストであるため、この動作によってリソースの消費も増加します。

次のステップ