格安に使えるGCEのプリエンプティブインスタンスの勝手に停止対策

概要

格安で使えるGCEのSpot VM(旧プリエンプティブインスタンス)。問答無用でシャットダウンされるというクセが困りものだが、使いようによってはハイスペックのインスタンスを安く効果的に使うことができる。ここではそのシャットダウン対策と最大限活用するためのヒントを紹介する。 機械学習用途ではVertex AI TrainingやGKE Autopilotなどマネージドサービスが充実しており、GCE直接利用は減少傾向にあるが、GPU/TPUを利用した機械学習ワークロードでコストを抑えたい場合などにSpot VMは有効である。

Google Compute EngineのSpot VMは

  • 最大24時間の制限は撤廃されているが、勝手に停止される(停止することをプリエンプト=preemptするという)
  • 安い(同スペックの通常インスタンスの半額以下、1/3程度)

という特徴がある。ミッションクリティカルな用途には向かないが、何よりも安いのでCPUやメモリを大量に使う機械学習の処理をするには向いている。ただし停止された場合には最初からやり直しとなる。処理をプリエンプトされないうちに終わらせるのがいい(GCEの余剰リソースを使うインスタンスであるため、CPUを数多く使うほどプリエンプトされやすくはなる)

インスタンスがプリエンプト状態になると

  • 1分後に強制停止される
  • シャットダウンスクリプトが実行される

つまり停止1分前にスクリプトを実行できる。1分間の間に終了処理を入れることができる。 猶予は1分しかないので、大きなファイル(学習結果のスナップショットなど)の保存などはできない。 停止したことを通知し、必要に応じてインスタンスを再起動して再学習開始するなど、何らかの対応をできるようにするのがいいだろう。 ここではSlackに通知する方法を紹介する。

シャットダウンスクリプトで

#!/bin/bash
preempted=$(curl -Ss http://metadata.google.internal/computeMetadata/v1/instance/preempted -H "Metadata-Flavor: Google")

if [ "$preempted" = 'TRUE' ]; then
  project_id=$(curl -Ss http://169.254.169.254/computeMetadata/v1/project/project-id -H "Metadata-Flavor: Google")
  instance_name=$(curl -Ss http://169.254.169.254/computeMetadata/v1/instance/name -H "Metadata-Flavor: Google")
  timestamp=$(date +'%Y-%m-%d %H:%M:%S')
  cat <<EOF | curl -Ss -X POST "https://hooks.slack.com/services/xxxxxxxx/yyyyyyyyyyy/zzzzzzzzzzzzzzzzzzzz" -d @- -o /dev/null
payload={"username": "system monitor", "text": "$project_id / $instance_name is being preempted (${timestamp})"}
EOF
fi
bash

プロセスがストップされるのは仕方ないが、サーバ自体は常時(に近く)稼働させておきたいケース。 gcloud compute instances startコマンドを使うとインスタンスを起動できるが、すでに起動している場合は無視される。そこで 他のとりあえずgcloudコマンドだけ実行できればいいマシン

  • クラウドでも他サーバでも可
  • Google Cloud SDKがインストールされていればいい
  • 何らかの処理を行うわけではないので低スペックで十分
  • 常時稼働

を用意し、そこからSpot VMに毎分gcloud compute instances startコマンドを送る。プリエンプトされても(理論上)1分以内に再起動できる。サービスのダウンタイムも数分で済むということになる。 cronを使ってこれを自動実行すればいい。Cloud SchedulerとCloud Functionsの組み合わせで代替することも可能である。

* * * * * gcloud compute instances start インスタンス名 --project プロジェクト名 --zone ゾーン名
bash

複数のSpot VMを集中管理するのもあり。