## 概要
2018年夏のインターンおよびPEとして勤務した[薮内さん](https://github.com/ordovicia)とそのメンターである[谷脇](https://github.com/dtaniwaki)、[大村](https://github.com/everpeace)で開発した[Kubernetes](https://kubernetes.io/)クラスターのシミュレーターである[k8s-cluster-simulator](https://github.com/pfnet-research/k8s-cluster-simulator)のアルファ版をオープンソースとして公開しました。このシミュレーターはKubernetesクラスタに投入されるPodのワークロードを時間とともにシミュレートできるため、Kubernetesのスケジューラーを本番環境に投入する前に評価することができます。
## 開発の動機
PFNでは巨大なオンプレのGPUクラスタを持っており、その上でKubernetesを使って様々な実行時間の機械学習ジョブを研究者が実行しています。我々クラスターサービスチームのミッションの一つとして、GPUの利用率を向上させ費用対効果をあげることが挙げられます。一方で、研究者間で使えるリソースの平等さも考慮しなければなりません。これを実現させるために、我々はKubernetesのスケジューラーを独自で開発したり、Extender (例 [kube-throttler](https://github.com/everpeace/kube-throttler))を拡張したりしています。しかし、新しく開発したロジックを本番環境で走っている機械学習ジョブに影響させずに評価するのは難しく、また頻繁に試行錯誤を本番環境上で行うのは好ましくありません。バグのあるスケジューラーをデプロイしてしまった場合には研究者の仕事を止めてしまうことになるので、絶対に避けなければなりません。またスケジューラーのアルゴリズムを試すためだけに、大規模なクラスタを用意し、多くのワークロードを実際に可動させることも現実的ではありません。これらの理由からKubernetesのスケジューラーを評価するためのクラスタのシミュレーターの開発を開始しました。
## デザイン
シミュレーターを開発するにあたって以下のことを考慮しました。
- シミュレーター用のスケジューラーの実装を最小限の変更で本番環境で動かせるようにする。
- 時間をシミュレートすることで評価を高速化するとともに、通信や内部処理のレイテンシーがスケジューリングのロジックの評価に影響しないようにする。
- シミュレートするワークロードを自由に設計できる。
- 後段の分析のために様々なメトリックスを出力できる。
## アーキテクチャ
以下は簡単なフロー図になります。
[](https://tech.preferred.jp/wp-content/uploads/2019/04/k8s-cluster-simulator-Overview.png)
アイデアはすごく簡単です。シミュレーターはループのステップ毎にクロックを1つ進めます。各ステップでサブミッターにそのクロックで投入するPodがあるかどうかを聞いて、サブミッターは投入または削除するPodがあればPodのリストを返します。シミュレーターはPodのリストをスケジューラーに渡し、スケジューラーはBindするものと削除するPodを選んでイベントとして返し、シミュレーターがリソース管理を行います。そして、この時に処理されたPodのメトリックスをMetrics Loggerに出力する流れになります。
以下はハイレベルなクラス図になります。
[](https://tech.preferred.jp/wp-content/uploads/2019/04/k8s-cluster-simulator-Class-Diagram.png)
本シミュレーターでは拡張できる点は以下の2つになります。
### Submitters
シミュレーターの定義するインターフェースに沿っていれば任意の数、組み合わせのサブミッターを使用することができます。複数のサブミッターをシミュレーターにプラグインできるので、例えばAさんは朝たくさんのPodをサブミットする傾向があるが、Bさんは夕方たくさんのPodをサブミットする傾向があるといったシミュレーションをする場合、それぞれのユーザの振る舞いモデルを独立に開発してシミュレーターにプラグインできます。
また、サブミッターはクロック毎のメトリックスを受け取ることができるため、クラスターの利用状況に応じて挙動を変えることも可能です。
### Scheduler
スケジューラーの拡張方法は2種類あります。
Kubernetesのスケジューラー([kube-scheduler](https://kubernetes.io/docs/concepts/overview/components/#kube-scheduler))をそのままもしくは拡張したアルゴリズムを利用したい場合、kube-schedulerが用意しているのと同様, Prioritizer, Extender, Predicateをセットできるミミックスケジューラーが用意されています。kube-schedulerはキューベースのスケジューラーですが、複数のPodを条件に応じてまとめてスケジュールするような、例えばより複雑なスケジューラーをシミュレーションしたい場合には、シミュレーターが定義するインターフェースを実装するように少しラッパーメソッドを書くと、それも評価できるようになっています。
\*kube-schedulerの挙動については大村による[Qiita投稿](https://qiita.com/everpeace/items/601dc613a0f424fb5619)をご覧ください。
## ロードマップ
現在、シミュレーターの使いやすさを向上させ、またより現実的な環境をシミュレーションできるように、ベータバージョンに向けて以下の機能を開発しています。
- より疎結合なコンポーネント(例:スケジューラーとサブミッターにRPCインターフェースをサポート)
- よく使われるサブミッターの提供(例: 典型的な確率分布に従うサブミッター(一様分布、二項分布、ポアソン分布等)
- より多くのクラスターイベントへの対応(ノード故障、突発的なPod故障、ノード追加、削除)
- デファクトなプロッターツール(matplotlib, gnuplot等)で直接読み込める出力フォーマットのサポート
興味のある方は是非試していただいて、フィードバックをいただけると幸いです。