Blog
本記事は、2024年夏季インターンシッププログラムで勤務された上田 蒼一朗さんによる寄稿です。
こんにちは。PFN2024 夏季国内インターンシッププログラム「機械学習プラットフォームエンジニア就業体験 (Kubernetes/インフラ)」に参加していました、京都大学修士1年の上田蒼一朗です。私はPFNの機械学習基盤を開発、運用するCluster Servicesチームで、「Kubernetes scheduler simulatorのリソース同期機能の開発」というテーマで課題に取り組みました。
PFNのKubernetesスケジューラー
Kubernetesのスケジューラーとは、クラスタ内のPodをどのNodeに割り当てるかを決定するコンポーネントです。KubernetesではPodにNodeを割り当てることをスケジューリングと言います。スケジューラーはデフォルトでは、例えば特定のラベルを持ったNodeを優先的に選択したり、Podが要求するリソースを持っているNodeを選択したり、できるだけPodの分布に偏りがないようにしたりするようなアルゴリズムでスケジューリングを行います。
スケジューラーには、このスケジューリングアルゴリズムに対して拡張を行うための仕組みがあり、それらをプラグインとして実装できます。これを利用してPFNでは様々なスケジューラープラグインを実装しています。
PFNが開発したプラグインの例として、Gangスケジューリングを行うものがあります。これは複数のPodのグループに対し、それらをすべてスケジューリングするか、それともどれもスケジューリングしないかいずれかのみになるようなアルゴリズムを実装しています。例えばマルチノード分散学習を複数のPodとしてクラスタ上で実行するとき、これらのPodのうち1つでもスケジューリングされていなければ分散学習は実行できません。そのため他のスケジューリングされているPodがクラスタのリソースを無駄に占有する状態に陥ります。これを防ぐため、GangはこれらのPodを全て同時にスケジューリングすることができなければ1つもスケジューリングしないようにしてくれます。
その他PFNでのスケジューラーの拡張についての詳細は、実際に運用してわかった! 多種GPU混載Kubernetesクラスタの使われ方と運用省力化や2022年のPFNの機械学習基盤をご覧ください。
このようなスケジューラープラグインの開発にまつわる課題として、本番環境でしか再現しないバグが発生しやすくデバッグが難しいということあります。本番環境ではスケジューラーにかかる負荷が大きいことによりこのような事態が発生します。このようなバグを開発環境で発見しデバッグできるようにしたいということが本インターンシップの取り組みの前提としてあります。
Kubernetes scheduler simulator
Kubernetes scheduler simulator(以下、scheduler simulator)とはKubernetesのコミュニティによって開発されているOSSで、名前の通りKubernetesのスケジューラーの動作をシミュレートしてそれを可視化してくれるものです。 scheduler simulatorは内部で仮想的なKubernetesクラスタを持っており、これに対してNodeやPodなどのリソースを追加することができるようになっています。このクラスタ内で動いているスケジューラーは、その中に実装されているアルゴリズムがどのような評価結果を出してスケジュール先が決定されているかを記録しています。そして動画のように、その記録やクラスタ内のリソースをWeb UIからグラフィカルに見ることができるようになっています。また、PFNが実装しているようなカスタマイズされたスケジューラーもサポートされています。そのためスケジューラープラグインを開発する際、意図したとおりにスケジューリングしているか確認できるなどデバッグに有用なものになっています。
そこで、scheduler simulatorに開発しているスケジューラープラグインを入れ、そこに本番環境と同等な負荷をかけることで、導入で述べた課題を解決するということが考えられます。しかしscheduler simulatorで本番環境のクラスタと同様な負荷をかける機能はありませんでした。scheduler simulatorでPodを追加するためには手作業でWeb UIから操作を行うかkube-apiserverを直接叩く必要があります。また、scheduler simulatorの起動時に任意のKubernetesクラスタからそのリソースをインポートするという機能もあるのですが、これでも本番環境のようにコンスタントにPodが作成され続けるような環境を再現することはできません。
本インターンシップではscheduler simulatorの仮想的なクラスタの状態を、任意のクラスタに同期し続ける機能を実装しました。つまりこれによって、本番環境で作成・更新・削除されたPodをscheduler simulatorでも自動的に作成・更新・削除できるようになります。
syncerの動作
このscheduler simulatorでリソースの同期を行う機能のPoC実装にsyncerというものがありました。syncerは本番環境のクラスタを監視し、そこで作成・更新・削除といったイベントが起これば、それをscheduler simulatorのクラスタ内に反映させるという処理を行います。本インターンシップでsyncerのWIP状態だったPRをベースとして引き継ぎ、実際に動くように実装を行いました。
以下にsyncerのデモを示します。このデモでは本番環境で動作しているArgo CDに対してApplicationを作成します。すると本番環境でPodが3つ作成され、同時にscheduler simulatorでもsyncerによって同じPodが3つ作成されます。
また、以下にもう1つデモを示します。こちらのデモでは上のデモと同様に本番環境のクラスタにArgo CDを使ってPodを作成しているのですが、これに同期しているscheduler simulatorが2つあり、一方ではデフォルトのスケジューラーが動いており、片方ではカスタマイズされたスケジューラーが動いています。そのためこのようにそれぞれ異なったスケジューリング結果になっています。このようにスケジューラーの拡張アルゴリズムによる動作の違いをグラフィカルに見ることができるようになっています。
このsyncer機能はこちらのPRで実装されマージされています。syncer機能はv0.3.0でリリースされており、その他syncerの詳細や使い方についてはドキュメントに示されているので、そちらをご覧ください。
syncerの実装と設計
syncerは任意のクラスタの状態をscheduler simulatorに反映させ続けるというシンプルな機能ですが、実装の際には意外と多くの考慮事項があります。本節ではそのいくつかをご紹介します。
上位リソースの扱い
Kubernetesでは多くのPodがReplicaSetやDaemonSetなどの上位リソースによって管理されていることが多いです。これらのリソースまでsyncerによって同期してしまうと、scheduler simulator内で動作するコントローラーによって勝手にPodが作成されてしまいます。そのためsyncerはこれらのリソースは同期しないようにしています。
しかし、これによって1つ問題が起こります。本番環境でReplicaSetなどによってPodが作成されたとき、それをそのままscheduler simulatorに反映させると、これらのPodはReplicaSetによって管理されているため、scheduler simulator内にはこれらを管理しているRepicaSetが存在しないことになり、コントローラーによってこれらのPodが削除されるということが起こってしまいます。そこで、syncerはPodを本番環境からscheduler simulatorに同期するとき、それが上位リソースによって管理されていないものであるとして書き換えてから同期するようにしています。スケジューラーの関心はPodのみであり上位リソースのことを意識する必要がないため、このようにしてもスケジューリング結果への影響はありません。具体的には、このロジックはsyncer内で以下のようなコードで実装されています。
// If the pod has an owner, it may be deleted because resources such as ReplicaSet are not synced. pod.OwnerReferences = nil
本番環境クラスタでのPodの更新
syncerの機能を利用しているとき、本番環境のクラスタとscheduler simulatorでそれぞれのスケジューラーが動作しています。本番環境でPodが作成されてそれがスケジューラーによってスケジューリングされると、そのPodには更新処理が行われたことになります。この更新をsyncerがscheduler simulatorに反映させると、scheduler simulator内のPodは本番環境のスケジューラーによるスケジューリング結果が適用されます。するとscheduler simulator内のPodは本番環境のクラスタによってスケジューリングされることになり、scheduler simulator内のスケジューラーは動作しなくなります。scheduler simulatorの紹介をした際に述べた通り、scheduler simulatorの内部で動作しているスケジューラーがスケジューリングの過程を記録しています。つまりscheduler simulatorが動作してくれなければスケジューリング結果を記録することができません。そこでsyncerは本番環境のスケジュール済みのPodについては更新をscheduler simulatorに反映させないというポリシーでこれを防いでいます。
ただし、この方針ではスケジューリング以外によるPodの更新も無視することになります。例えばPodに対するラベルの付与や、Podのリソースの更新(In-place Resource Resize)などが起こると、これによってスケジューリング結果が変わる可能性があります。このようにPodの更新を反映しないことで本番環境のクラスタとscheduler simulatorでズレが発生しますが、メンテナと議論した結果これについては許容するという判断をしました。この機能の目的はあくまで本番環境と同じ規模の負荷をscheduler simulatorにかけることなので、ある程度本番環境とのズレが発生することは問題ありません。むしろ本番環境と全く同じ環境を再現し続けることは非常に困難です。また、ラベルの付与によってスケジューラーの動作が変わったり、Podのリソースが再起動なしで行われたりすることは稀なケースなので、これらによるズレはそもそも起きにくいということも理由の1つです。
scheduler simulatorでのPodの削除
scheduler simulator内でPodの削除が起こったときにどうするかということにも議論がありました。scheduler simulatorでPodの削除が起こるケースとして、以下の2つのケースが想定されます。
- schedulerによるpreemption
- ユーザーによる手動削除
結果的にはどのケースかに関わらず、scheduler simulator内でPodが削除されても何も対応せずそのままにしておくというポリシーを採用しました。まず1つ目のケースについては、preemptionが起こるほどscheduler simulator内の仮想的なクラスタが逼迫している状況では本番環境でも同様に逼迫しているはずであり、そのうち本番環境でもpreemptionによってそのPodが削除される可能性が高いため、長期的に見れば本番環境とscheduler simulatorとの差は大きくならないという見通しの元、無視しても構わないと判断しました。また2つ目のケースについて、ユーザーが手動でscheduler simulatorのPodを削除するのはscheduler simulatorのデバッグをするときぐらいしかないため、むしろデバッグを邪魔しないよう何もしないほうが良いと判断しました。また、逆にデバッグ時以外はscheduler simulatorでPodを削除しないようドキュメントに明記しました。
感想
本インターンシップではKubernetes scheduler simulatorにリソース同期機能syncerを実装しました。また手元で実装するに留まらずこの機能をアップストリームにマージしてもらうところまで完了しました。これらの取り組みを通してOSSの開発の一連の流れを体験しました。特に前節で述べたsyncerの設計事項についてメンテナと直接議論できたことは私にとって貴重な経験でした。OSSでの開発は企業内に閉じた開発とは異なり、メンテナをはじめとしたコミュニティのメンバーとインターネット上でコミュニケーションを取り合意形成を行わなければなりません。その過程で、実装する機能についてどう認識を合わせて議論を進めていくかということを体験しながら学べました。この経験を活かして今後もOSSの開発に取り組んでいきたいと思います。
最後にメンターの小松さん、Cluster Servicesチームの皆さん、そしてKubernetes scheduler simulatorのメンテナであるKensei Nakadaさんには大変お世話になりました。この場を借りて感謝申し上げます。
メンターより
上田さんのメンターを務めました、PFN Cluster Services チームの小松です。
Cluster Services チームでは例年 7 週間のサマーインターンを行っておりますが、上田さんには今年から新設した 2 週間インターンに従事いただきました。インターン内でのイベントを除くと開発ができるのは実質 7 営業日しかなく、短い期間だったにも関わらず、集中して取り組みしっかり成果を出してくれました。
本インターンではOSSのメンテナへの提案や議論などを精力的に取り組んでいただきました。また、実装して頂いた機能のマージまで精力的に取り組んでいただき、無事にマージ、リリースまで達成されました。
本インターンでの成果は前述のとおりリリース済みなのでぜひ触ってみてください!
また、重ねてにはなりますが、Kubernetes scheduler simulatorのメンテナであるKensei Nakadaさんに協力をいただき、本機能を実装できたことも強調させていただきます。ありがとうございました。
PFN では、機械学習/深層学習そのものの研究だけでなく、それらを支えるクラスタの研究開発、構築、運用も行っています。OSS に対するコントリビューションや開発したツールの OSS 公開も、業務の一環として取り組めます。ご興味がある方、ご応募をお待ちしております。
Area
Tag