Kubernetes Engine クラスタのパワーを最大限に引き出す Priority と Preemption
Google Cloud Japan Team
最も重要なワークロードが常に Kubernetes クラスタのリソースを確保できるようになればいいと思いませんか? これが Kubernetes 1.9 で可能になりました。新たに導入された “Priority” および “Preemption” というアルファ機能を使用すれば、ワークロードに優先順位を付けることができます。これにより、クラスタのリソース利用が上限に達した場合には、この優先順位に応じて重要なポッドがそうでないポッドを退避させます。
Priority と Preemption の導入前は、Kubernetes ポッドが純粋に早い者勝ちでスケジューリングされ、起動されたポッドは最後まで実行されていました(Deployment や StatefulSet などで作成されたポッドの場合は永遠に)。そのため、重要度の低いワークロードが、後から来た重要度の高いワークロードをブロックし、実行できなくしてしまうことがあったのです。これは望ましいことではありません。Priority と Preemption は、この問題を解決します。
この機能が役に立つシナリオはさまざまです。たとえば、コスト管理のために自動スケーリングのクラスタ サイズに一定の上限を設けたいときや、リアルタイムで拡張できないクラスタがあるときです(たとえばクラスタがオンプレミスにあり、ハードウェアを増設するには購入およびインストールが必要な場合)。高優先度のクラウド ワークロードを、クラスタの自動スケーラによるノード追加を待たずに、迅速にスケールアップしなければならないときもそうです。
Priority と Preemption は、リソースをうまく活用し、コストを下げ、特に重要なアプリケーションのサービス レベルを上げることに貢献します。
安全性を犠牲にせずにクラスタのコストを予測可能に
昨年、Kubernetes コミュニティはシステムのスケーラビリティとマルチテナンシーのサポートという点で大きな進歩を遂げました。その結果、ユーザーと直接やり取りするクリティカルなワークロード(ウェブ サーバー、アプリケーション サーバー、バックエンド、サービスを直接提供するパスに含まれるマイクロサービスなど)と、時間に余裕のあるワークロード(日次および週次のデータ分析パイプライン、臨時のアナリティクス ジョブ、開発者の実験など)の両方を実行する Kubernetes クラスタが増えています。このような形でクラスタを共有すると、前者の “リソース ホール”(リソースを使っていないにもかかわらず、使用料を払っている時間)のときに後者を部分的あるいは最後まで実行できるようになり、コスト効率が上がります。実際、Google が実施した社内ワークロードに関するある調査では、クリティカルなワークロードとそうでないワークロードをクラスタで共有しないとすると、コストが約 60 % も上昇することがわかりました。ノード サイズを柔軟に変更でき、リソースのフラグメンテーションも少ないクラウドでは、Kubernetes の Priority と Preemption が劇的な効果を生むことはないでしょうが、一般的な条件は同じです。
従来は、重要度の低いワークロードを BestEffort として実行する方法で未使用リソースを活用していました。しかし、BestEffort ポッド用のリソースは明示的に予約されないため、ノードがメモリを使い切ると、それらのポッドは、たとえわずかなリソースしか使っていなかったとしても、CPU を割り当ててもらえなくなったり終了させられたりしてしまいます。
すべてのワークロードを Burstable や Guaranteed として実行し、いずれにもリソースを確実に割り当てるようにすれば、この問題は解決できますが、予測可能なコストとロード スパイク発生時の安全性との間で二者択一を迫られます。
たとえば、クラスタが非クリティカルなワークロードでビジー状態になっているときに、ユーザーとやり取りするサービスにロード スパイクが発生したとします。このとき、クラスタの自動スケーラの上限を非常に高くするか、もしくは上限を設定していなければ、発生したロード スパイクに対応でき、安全性を確保できますが、コストの予測がつかなくなります。これとは逆に、自動スケーラの上限をタイトに設定するとコストの予測はつきますが、予想外の負荷が発生したときに十分にスケールアップできません。
こうしたジレンマは Priority と Preemption を導入すれば解消できます。クラスタがリソースを使い切ったら、Kubernetes が非クリティカルなワークロードのポッドを退避させるので、クラスタ サイズに上限を設定していても、トラフィック スパイクの発生時に十分にスケールアップできなくなるのではないかという心配はなくなります。なお、ポッドが退避させられても、強制終了の前に猶予時間が与えられます。この時間のデフォルトは 30 秒です。
コストの予測可能性と安全性との二者択一問題がない場合でも、Priority と Preemption は役に立ちます。Preemption によって、クラウド プロバイダーが Kubernetes ノードをプロビジョニングするよりも早くポッドを退避させられるためです。
たとえば、ユーザーとやり取りする優先度の高いサービスにロード スパイクが発生したときは、その負荷を吸収するために Horizontal Pod Autoscaler が新しいポッドを作成します。クラスタ内で優先度の低いワークロードが実行されている場合、新しい優先度の高いポッドは、優先度の低いワークロードのポッドが退避したらすぐに実行を開始できます。クラスタの自動スケーラによって新しいノードが作られるのを待つ必要はありません。
その後、クラスタの自動スケーラによって新しいノードが追加されたら、優先度の低いワークロードのポッドも再び実行を開始します(Priority と Preemption をこのような形で使うときは、優先度の低いワークロードの実行中止までの猶予時間を短く設定し、優先度の高いポッドがすぐに実行を開始できるようにすることが、グッド プラクティスになります)。


Kubernetes Engine で Priority と Preemption を有効にする方法
このほど Google Kubernetes Engine が Kubernetes 1.9 に対応し、アルファ クラスタで Priority と Preemption を利用できるようになりました。その方法は次のとおりです。- アルファ クラスタを作成します。記載されている制限に注意してください。
- 指示に従い、Kubernetes クラスタに少なくとも 2 つの PriorityClass を作成します。
- 作成した PriorityClass のいずれかに合わせて priorityClassName フィールドを設定し、ワークロードを作成します(Deployment、ReplicaSet、StatefulSet、Job などを使用)。
必要なら、クラスタの自動スケーラを有効にしてクラスタ サイズの上限を設定します。その場合、クラスタは設定された最大ノード数以上に拡張しません。クラスタ サイズが上限に達し、優先度の高いクラスに保留ポッドがあると、優先度の高いポッドが優先度の低いポッドを退避させます。
クラスタの自動スケーラを有効にしない場合は、クラスタ サイズが固定されるだけで、Priority と Preemption の動作は同じです。
高度なテクニック : リソース ホールの強制的な “穴埋め”
先に述べたように、Priority と Preemption の導入を促す理由の 1 つは、重要なワークロードとワークロードの間に生じるリソース ホールを、非クリティカルなワークロードで埋めることができる点です。優先度が負数の PriorityClass をワークロードに関連づければ、この動作を厳密に強制できます。この場合、クラスタの自動スケーラは、クラスタのノード数が上限の設定値に達していなくても、そのワークロードの実行に必要なノードを追加しません。以上からわかるように、重要度の高い順に次の 3 種類のワークロードを作ることができます。
- クラスタの自動スケーラの上限までクラスタにアクセスできるワークロード
- 自動スケーリングをトリガーできるものの、クラスタ サイズが上限に達して優先順位の高いワークロードを実行しなければならなくなると、退避させられるワークロード
- 優先度の高いワークロードによってリソース ホールが生じたときに、その穴埋めをするワークロード。つまり、既存の未使用リソースに収まりきらなければ、実行されずに待機するワークロード
PriorityClass は整数で指定されるため、この 3 つのカテゴリー内でサブの階層を作ることもできます。
ご意見をお聞かせください
Priority と Preemption は、リソース利用とコスト管理をしやすくするとともに、ワークロードの優先度を明確化できる Kubernetes 1.9 の歓迎すべき新機能ですが、まだアルファの段階にあります。この機能をどのように使っているか、より良くするにはどうすべきかといったご意見をこちらまでお寄せください。また、12 か月間の無料トライアルを利用して、この新機能や Kubernetes Engine のその他の機能をぜひお試しください。
* この投稿は米国時間 2 月 14 日、Google Kubernetes Engine の Software Engineer である Babak Salamat と David Oppenheimer によって投稿されたもの(投稿はこちら)の抄訳です。
- By Babak Salamat and David Oppenheimer, Software Engineers, Google Kubernetes Engine