HOME/Articles/

比較:kubernetesとOpenStack Novaのスケジューリング

Article Outline

比較対象

OpenStack Novaでインスタンス配備時に、nova.confに定義されているschedulorを使用して、配備先を決めます。 kubernetesの管理対象はpodであり、そもそも仮想化方式が違うが、「アルゴリズムに従ってリソースの配備先を決める」という意味で、 スケジューリングの考え方を比較可能だと思います。

復習:OpenStack Novaのスケジューリング

参照先:https://docs.openstack.org/mitaka/config-reference/compute/scheduler.html

基本的な考え方として、フレーバーに定義されているリソースの容量に応じて、nova schedulerは以下の流れてインスタンスの配備先を決めます:

  1. 定義されたfilterで複数の配備先ホストを選定
  2. 選定されたホストのそれぞれのweight値を算出
  3. weight値の大きい順で優先順位を付けていく

filterをする際に、いろいろな条件でホストを選別します。デフォルトの設定でも、以下の9種類のfilterが適用されます。

  • RetryFilter:まだ選別されたことがないホスト、つまり、「新鮮」なホストを優先する
  • AvailabilityZoneFilter:指定されるAvailability-zoneに所属するホストのみ選出
  • RamFilter:必要なメモリ容量があるかをチェック
  • DiskFilter:必要なディスク容量があるかどうかをチェック
  • ComputeFilter:最も基本なチェック、nova-computeサービス自体は稼働中であれば通過
  • ComputeCapabilitiesFilter:フレーバーに定義されるメタデータをチェック
  • ImagePropertiesFilter:イメージに定義されるメタデータをチェック
  • ServerGroupAntiAffinityFilter:同じグループに所属するインスタンスを違うホストに分散配置、高可用性の場面を想定
  • ServerGroupAffinityFilter:同じグループに所属するインスタンスを同じホストに集中配置、データ依存の場面を想定

それ以外もたくさんのfilterが用意されており、高級的な使用方法ならカスタマイズのfilterも作成可能です。

極端の場面以外に、filterを通過できるホストは複数であるので、さらに「重み(weight)」をそれぞれのホストに対して算出します。 式として:

重み = 属性値1*乗数1 + 属性値2*乗数2 + 属性値3*乗数3 + ...

具体的な属性はコンピュータドライブに依存します。計算する際に、各属性値は正規化されているため、数値単位による影響がないです。 使用する属性値と乗数はそれぞれnova.confの中に指定できます。

最後に、重みの値は最も大きいホストを配備先として決めます。

比較しながら、Kubernetesでスケジューリングを勉強

参照先:https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/

まず、対象はコンテナになっているが、スケジューリングの基本機能は変わりません。ワークロードの管理単位であるpodの起動先ノードを見つけることです。 簡単に並べてみると、podはインスタンスに相当し、ノードはcomputeノードあるいはHypervisorに相当するでしょう。 上記ドキュメントをみると、デフォルトのスケジューラーは「kube-scheduler」というものです。podの稼働条件に合わせて、 「feasible」のノードをまず選出して、選出されたノードに対して、「score」を算出し、高い「score」のノードにpodを起動させます。 これまでに、openstackの用語と比べて、新しい用語が出て来るが、処理プロセスには違いがないと思います。

これから差異が出始めます。OpenStackの場合は、インスタンスを作成する際に、フレーバーを指定することで、「これぐらいのリソースを使用する予定ですよ」 と自己申告します。本当にいっぱいまで使用するかは別として、まず確保してくれる必要があります。 これに対して、podを起動する際に、「request」と「limit」を両方申告します。つまり、「最低でもこれぐらい欲しいが、 余裕があればもっと割り当てくれればよくて、上限値を超えないように約束します。」という柔軟性が効く申告方法となります。 ノード上のkubeletサービスが、各podの申告内容をまとめて管理し、システムの安定性に影響しない限り、「みんな自由に使ってください」という ポリシーで管理します。 OpenStackの場合は、リソースを追加で確保もできるが、「resize(フレーバー変更)」のような運用操作は必要です。 仮想マシンからコンテナに切り替えることで、より柔軟にリソースの配分ができて、利用率が向上したと考えられるでしょう。

OverCommitの場面はどうなるか

仮想マシンベースのクラウド環境では、リソース使用率を上げるために、「overcommit」を使用することは大前提です。overcommit対象のリソースが CPU、メモリ、ストレージなどいろんな種類があります。今回、CPUとメモリを例として、仮想マシンとコンテナプラットフォームの違う考え方を考察したい と思います。

参照先:https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-resource-requests-and-limits

OpenStack環境のHypervisorは何種類もありますが、デフォルトのKVMの場合はどうなるでしょうか:

  • CPUはovercommitによって負荷超過になる場合は、物理CPUは100%以上使えないので、想定通り輻輳になります
  • メモリの場合は、物理メモリが足りなければ、SWAP領域への書き出しが始めるので、処理が遅くなります。 結果的に、「勝手に仮想マシンを止まるとダメなので、同じHypervisor上に稼働するみなんの仮想マシンを一緒に我慢してください」というポリシーです。

kubernetesの環境なら、処理の仕方は違います。上記Googleのドキュメントに書いてあるように、負荷超過が発生する際に、ロジックに従って、 リソースを食うpodを停止させます。優先度として: 第一優先:そもそもrequestを設定していない、つまりリソースの申告はそもそもしないもの 第二優先:requestのリソースを超えており、かつプライオリティが低いもの、過少申告しおり、かつVIPではないので、しょうがない 第三優先:プライオリティが同じであれば、requestを最も超えているもの、つまり、一番改善効果を見込めるので

最後に

スケジューリングの話はこれぐらい簡単のものではないので、今後継続的にふり返しが必要と思います。 コンテナ基盤になると、柔軟性と自由度は以前の仮想マシンのプラットフォームより改善したが、それ分を注意を払う必要があリます。 今まで、仮想マシンを停止させないように、いろいろな工夫があるが、「Cloud-Nativeの時代なら、アプリは停止するもの」ということ を常に意識して開発を行うと無難でしょう。