先日行われた Kubernetes Meetup Tokyo #16 で、現在 Scheduling SIG で進められているプロジェクト Scheduling Framework について発表してきました。
Kubernetes では、Pod をどの Node に配置するかを決める手続きをスケジューリングと呼びます。
古典的な Kubernetes の用途、すなわち通常の long-running なサーバ群の管理においては、Pod のスケジューリングは比較的シンプルな問題でした。すなわち、Node の障害時でも可用性が保てるように Pod を複数の Node に散らし、一度立ち上がった Pod は基本的に動き続ける、というシナリオです。
しかし、Kubernetes は既にコンテナスケジューラのデファクトを獲得し、様々な性質を持ったアプリケーションがデプロイされる基盤となりました。この流れの中で、デフォルトの kube-scheduler ではカバーできないような複雑なスケジューリングの需要も生まれています。
この問題を解決するためのプロジェクトが Scheduling Framework です。本記事では、スライドに登場した用語や概念について、Scheduling SIG その他から提供されているドキュメントやサンプルを紹介します。
Scheduling SIG によるサブプロジェクト
kube-batch
kube-batch はバッチ処理向けのスケジューラで、かつて kube-arbitrator と呼ばれていたプロジェクトが改名しました。たった 1 行だけの Wiki が味わい深いです。
PodGroup
を指定することで複数の Pod を組にして扱う機能を備えているのが特徴で、この仕組みは Kubernetes を機械学習用基盤として使用する kube-flow プロジェクトにも導入されるようです。
Poseidon
Poseidon は、グラフ理論を利用して複雑かつ効率的なスケジューリングを目指す新機軸のプロジェクトです。
元になっているのは Firmament Scheduler と呼ばれる汎用のタスクスケジューリングの仕組みで、配置の制約を最小費用流問題に帰着させて最適化を行うようです。Kubernetes の Pod と Node に対して Firmament を実装したものが Poseidon という関係になっています。
正直なところ、この記事を書いている時点ではまだ論文を充分読み込んでいないので何とも言えませんが、内容がきちんと把握できたら改めてどこかのイベントで発表したいと思います。
Scheduler Extender
スケジューリング処理の一部分を JSON Webhook で外部サーバに委譲するための仕組みが Extender です。
Extender が設定できる処理は以下の 4 か所で、Scheduler 起動時の設定ファイルに外部サーバのエンドポイントなどを記述することで有効になります。
- Filter - 後段の順序付けフェイズに候補として残す Node を絞ることができます。リクエストはデフォルトのフィルタリングプロセスを通過した Pod、レスポンスはフィルタリング後の Pod です。
- Prioritize - 最良の Node を選択するためのスコアリング関数を追加できます。引数はフィルタリングで残った Pod、レスポンスは Node ごとのスコアです。
- Preempt - Pod の Preemption が発生する際に、犠牲となる Pod を消極的に選択することができます。リクエストは Node ごとに犠牲となる予定の Pod、レスポンスは実際に犠牲にする Pod です。
- Bind - Pod を Node に配置する前の準備などを行うことができます。ただしその場合、Pod と Node を結びつけている
Binding
リソースの作成まで含めて自分で行う必要があります。Pod の情報と Node 名がリクエストされます。
なお、上記のドキュメントは古いためか Preempt Extender の記載がありませんが、ソースコードを見ると実装されていて実際に動きます。
もし Extender を使用したい場合は、ドキュメントよりもむしろ、構造体の定義および @everpeace さんによる実装サンプルを参考にするとよいでしょう。
Scheduling Framework
Scheduling Framework のプロポーザルです。今回のスライドは基本的にこのプロポーザルに沿って説明しています。
上でも挙げたような特定用途のために作られたスケジューラは、基本的にスクラッチから開発されています。というのも kube-scheduler の実装は歴史的事情から抽象化が十分でなく、拡張性に限界があるためです。
そこで、Scheduling Framework では設計を刷新して新しい拡張点を定式化します。それぞれの拡張点では、Go のインタフェースとして実装されたプラグインを登録し処理を差し込めるようにするとともに、プラグイン同士が情報をやり取りできる仕組みが構築される予定です。
そう、あくまでも予定です。 プロポーザルには多数の拡張点が述べられていますが、現状で以下の二点のみ実装されています。
- Reserve - Node が確定した後、Pod ごとの goroutine が生成される前
- Pre-Bind - Pod ごとの goroutine に入った後、API Server に Binding が登録される前
この二点は、Pod を配置する Node に前もって何かを準備する処理を想定したもので、典型的な用途はネットワークストレージをボリュームとして確保するというものです。
従来、ボリュームの確保とバインドは assumeVolume
と bindVolume
という専用の関数で行われています。一方 GPU などボリューム以外のネットワークリソースについてはユーザが Bind Extender という形で各自実装する必要があります。
そこで、assumeVolume
に相当するものとして Reserve プラグインを、bindVolume
に相当するものとして Pre-Bind プラグインを実装し、リソース関連の処理を統合して抽象化することが Scheduling Framework の第一弾として意図されていました。が、今のところ拡張点が準備されただけで止まっており、assumeVolume
も bindVolume
もそのまま残っています。まあ、今後の展開を見守りましょう……。
まとめ
本記事では、Kubernetes スケジューラの再設計を目的としたプロジェクト Scheduling Framework と、その周辺トピックについて紹介しました。Scheduling SIG のマンパワー不足もあって、当初の予定ほど華々しい進展が見られないのは残念ですが、それはまた別の話。