GKE Autopilot の Spot Pod とプリエンプションの関係

Google Cloud Platform Advent Calendar 2021 の 9 日目の投稿です。
(執筆を予定されていた方が投稿されなかったため代わりに投稿させて頂きます)

先日、GKE Autopilot で Spot Pod が利用可能になりました(執筆時点ではプレビュー)。
Google Cloud の Blog に投稿されたアナウンスの記事は こちら

中断可能なワークロードに対して大幅なコスト削減が期待できるオプションですが、活用にあたっていくつかの制約を理解しておく必要があり、この記事ではそのひとつとして Spot Pod のシャットダウン時の仕様について触れたいと思います。

Spot Pod とプリエンプション

Spot Pod は、Spot Pod の利用をリクエストするための nodeSelector または affinity を Pod のテンプレートに付与することで、GKE Autopilot が GCE の Spot VM を自動でプロビジョニングして Spot Pod をデプロイする、というかたちで使用されます。

GKE 1.20 以降の Preemptible VM / Spot VM では、Graceful Node Shutdown が有効化&設定されています。
利用している Spot VM がプリエンプションの対象となった場合は、Pod を安全に終了させるための猶予期間がリクエストできるようになっており、最長 25 秒 ※ の猶予期間をリクエスト可能です。

※ Autopilot ワークロードの Spot Pod をリクエストする
https://cloud.google.com/kubernetes-engine/docs/how-to/autopilot-spot-pods#request-spot-pods

プリエンプションでの Spot Pod の最大猶予期間は 25 秒です。

このリクエストできる期間の長さは Graceful Node Shutdown の設定によって上限が決まる仕組みになっています。
実際の設定を見てみましょう。

apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
  x509:
    clientCAFile: /etc/srv/kubernetes/pki/ca-certificates.crt
authorization:
  mode: Webhook
cgroupRoot: /
clusterDNS:
- 10.12.0.10
clusterDomain: cluster.local
enableDebuggingHandlers: true
evictionHard:
  memory.available: 100Mi
  nodefs.available: 10%
  nodefs.inodesFree: 5%
  pid.available: 10%
featureGates:
  DynamicKubeletConfig: false
  ExecProbeTimeout: false
  GracefulNodeShutdown: true
  InTreePluginAWSUnregister: true
  InTreePluginAzureDiskUnregister: true
  InTreePluginOpenStackUnregister: true
  InTreePluginvSphereUnregister: true
  RotateKubeletServerCertificate: true
kernelMemcgNotification: true
kind: KubeletConfiguration
kubeReserved:
  cpu: 1060m
  ephemeral-storage: 41Gi
  memory: 1019Mi
readOnlyPort: 10255
serverTLSBootstrap: true
shutdownGracePeriod: 30s
shutdownGracePeriodCriticalPods: 5s
staticPodPath: /etc/kubernetes/manifests

Autopilot ではノードの設定が参照できないため、上記では GKE Standard で Spot VM としてプロビジョニングしたノードの kubelet の設定を参照しています(kubelet v1.21.5-gke.1302, cos-containerd, Spot VM の設定で GKE Standard にプロビジョニングしたノードの kubelet-config )。
Autopilot がプロビジョニングする Spot VM と全く同じ設定かどうかは確認する術がありませんが、ドキュメントを読む限り Graceful Node Shutdown まわりの設定は同じような設定になっていると考えても良さそうです。

設定内容を見てみると、kubelet の featureGates で Graceful Node Shutdown が有効化されています。
Graceful Node Shutdown に関連するパラメータは以下のふたつです。

  • shutdownGracePeriod: 30s
  • shutdownGracePeriodCriticalPods: 5s

Kubernetes の Graceful Node Shutdown のドキュメント ※ を読むと、ノードのプリエンプション時に Pod がリクエスト可能な terminationGracePeriodSeconds の最長期間は、CriticalPods と呼ばれるシステム系の Pod(Pod Priority が system-cluster-critical または system-node-critical)と、それ以外の Pod を区別して設定できるようになっています。
通常の(システム系以外の)Pod については、 shutdownGracePeriod の値からshutdownGracePeriodCriticalPods の値を引いた残り時間が、リクエスト可能な terminationGracePeriodSeconds の最長期間となります。

※ Graceful node shutdown
https://kubernetes.io/docs/concepts/architecture/nodes/#graceful-node-shutdown

GKE 1.20 以降の Preemptible VM / Spot VM では、上記の設定により (shutdownGracePeriod) - (shutdownGracePeriodCriticalPods) = 25 秒 が terminationGracePeriodSeconds でリクエスト可能な最長期間であることがわかります。
これが Spot Pod や、Spot VM で実行する Pod の terminationGracePeriodSeconds の上限としてドキュメントに記載されているということですね。

まとめ

Spot Pod のシャットダウン時の仕様と、(GKE Standard の Spot VM の設定から得られる推測を含みながらではありますが)それを実装している Graceful Node Shutdown の設定を確認しました。

Spot Pod のシャットダウンについては以下を認識しておくと良いでしょう。

  • Spot Pod は載っているノードのプリエンプションが発生した際に Pod を安全に終了させるための猶予期間が指定できる(terminationGracePeriodSeconds)
  • Spot Pod の terminationGracePeriodSeconds は最大 25 秒がリクエストでき、それ以上の値を指定しても無視される
  • Spot Pod の terminationGracePeriodSeconds はあくまでもリクエストであり、指定しても必ずその猶予期間が確保されるとは限らない

以上です。