GKEでプリエンプティブインスタンスを使いこなす

GCPにあるプリエンプティブ インスタンスをGKEでうまいこと使えないか、試行錯誤した結果をまとめます。

プリエンプティブ インスタンスとは

一言で言ってしまえば、AWSにあるスポットインスタンスGCP版です。

公式ドキュメントにはこのように書いてあります。

プリエンプティブ VM は、最長持続時間が 24 時間で、可用性が保証されない Google Compute Engine VM インスタンスです。プリエンプティブ VM は標準的な Compute Engine VM よりも低価格で、同じマシンタイプとオプションを使用できます。

ドキュメントに書かれているように低価格で使用できるのが最大のメリットです。
だいたい1/3ぐらいの価格で使用することができます。

f:id:akaimo3:20180722164618p:plain

しかし、様々な制限があります。
意識しておかなければならないこととして、次のようなことがあります。

  • いつ終了するかわからない
  • 最大でも24時間でシャットダウンされる
  • 常に使用できるとは限らない

これらの注意点と上手に付き合いながらGKEのNodeとして使用していきます。

使いこなす

シャットダウンの対策

まず、シャットダウンによりNode数が減ってしまう問題はGKEを使っている上では問題ありません。
KubernetesがNode数の減少を検知して、即座に元と同じ数になるようにNodeを起動し直してくれます。

しかし、一時的とはいえNodeが減るので、そこで可動しているPodは止まってしまします。
すぐに復帰するので、冗長化されているPodであればそこまで問題でもありません。せいぜい、一時的(数秒から数十秒)に別のPodに負荷が集中するぐらいです。

アプリケーションの構成などの理由により冗長化できないPodや一時的でも減っては困るPodに対しては、プリエンプティブ インスタンスに配置されないように設定をします。

プリエンプティブ インスタンスの回避

Kubernetesのtaintsとtolerationsという機能を使用してプリエンプティブ インスタンスを回避します。

まず、通常のインスタンスで構成されるノードプールとは別に、プリエンプティブ インスタンスだけで構成されたノードプールを作成します。 プリエンプティブのノードプールを作成するときに、ノードtaintを設定します。

f:id:akaimo3:20180722171308p:plain

そして、プリエンプティブ インスタンス配置されても問題ないPodにtolerationを設定します。

spec:
  template:
    spec:
      containers:
      ...
      tolerations:
        - key: gke-preemptible
          operator: Equal
          value: "true"
          effect: NoSchedule

これでこの設定がされているPodのみがプリエンプティブ インスタンスのノードプールに配置されるようになります。

taintsとtolerations

ちょっと仕組みがわかりにくいので、taintsとtolerationsの概念を説明します。

Nodeにtaints(よごれ)をつけ、そのtaintsをtolerations(寛容、黙許)できないPodをNoSchedule(スケジュールしない)と設定しています。
そしてPodにtolerationするtaintの内容を記述することで、taintのついたNodeに配置されるようになります。

24時間でシャットダウンされる

上で書いたプリエンプティブ インスタンスの回避の設定をしていれば24時間でシャットダウンされる制限も問題ないように感じるかもしれません。
しかし、24時間たつ前にシャットダウンされることがなかった場合、ノードプール内の複数のインスタンスが同時に24時間を経過し、同じタイミングでインスタンスがシャットダウンする可能性があります。

これだと、いくら冗長化していても運しだいですべてのPodが消えてしまう可能性があり、リスクが高くなります。

この問題の解決方法は簡単で、ノードプールを追加後、起動時間がバラけるように一部のNodeをシャットダウンしてしまえば良いです。
そうすることで複数のNodeが同時に24時間を迎えてシャットダウンされることが防げます。

常に使用できるかわからない

プリエンプティブ インスタンスがシャットダウンされたあと、GCPの状況によってはプリエンプティブ インスタンスが起動できないことがあります。

この場合、通常のインスタンスで構成されるノードプールにクラスターのオートスケールを設定しておくことで、そっちにインスタンスが追加されPodが配置されます。
tolerationsの設定がされていれも問題なく通常のインスタンスに配置されます。
なぜならtolerationsはtaintsを受け入れる設定なので、taintsが無いNodeにも配置されます。

まとめ

これを意識することでGKEを低価格で運用することができます。
ぜひ試してみてください。