はじめに
これはKubernetes Advent Calendar 2021 4日目の記事です。
今回はAWSが先週GAを発表した「Karpenter」について、実際に触ってみた様子とOSSとしての思想やデザインについて書いてみます。
Karpenterとは
Karpenterの公式ページでは「Just-in-time Nodes for Any Kubernetes Cluster」と説明があります。つまり、KubernetesノードをPodが必要とした瞬間に用意するようなプロダクトを目指していることになります。まずは前提を揃えるためにKubernetesのオートスケーリングについて簡単に説明します。
Kubernetesのオートスケーリング
Kubernetesにおけるオートスケーリングには大きく分けてコンテナ(Pod)レベルのスケーリングとノードレベルのスケーリングがあります。「HPA(Horizontal Pod Autoscaler)」や「VPA(Vertical Pod Autoscaler)」などのリソースはPodレベルのスケーリングを実現してくれますが、ノード自体のオートスケールをしたい場合は「Cluster Autoscaler」というアドオンが必要で、これはAWS、GCP、OpenStack、vSphereなどのCloud Provider APIが使える環境でないと基本的には動きません。
Karpenterではノードを必要に応じて作ったり消したりをしてくれるので、Cluster Autoscalerに相当する機能を持っていることになります。これまでの仕組みとどのように違うのか、現状サポートされているEKSでの動作の違いに着目してみることにします。
※公式ドキュメントでも記述がありますが、Karpenter自体はどのKubernetesでも動作するように設計されて作られています。将来的にオートスケールを別の仕組みでできるようなアドオンができるかもしれませんが、現状の公式サポートはAWSのみとなっています。
既存のCluster AutoscalerとEKSを組み合わせた場合の動き
EKSを使う場合、クラウドリソースとしては大きく分けて次の2つを用意することになります。
AWS::EKS::Cluster
AWS::EKS::Nodegroup
このとき、NodegroupリソースはセルフマネージドのEC2インスタンスを代わりに使ったり、あるいはFargate profileを用意してそこにノードをスケジュールさせるという選択肢もありえます。いずれにせよ、図にすると以下のような形でこれまではKubernetesリソースを用意していました。
Fargateの場合はFargate側のスケジューラーがオートスケーリングまで管理しますが、EC2タイプの場合はCluster Autoscaler on AWSのドキュメントにも記述があるように、AWSのAuto Scaling groups(ASGs)がEC2の水平スケーリングを管理します。つまり、EKSのノードグループというのはほぼほぼAWSのオートスケーリンググループと同義であるという見方もできます(もちろん起動テンプレートだとかそれに付随する他のリソースもありますがここではファクターではないので無視)。実際、ノードグループを作成するとそれに1対1で紐づく形でAWS上にAuto Scaling Groupが作成され、ノードグループリソースのプロパティで設定したノード数はそのASGに反映されていることがわかります。
KarpenterにおけるCA(Cluster Autoscaler)への優位性
Karpenterのドキュメントには、CAへの優位性として以下の項目が挙げられています。
クラウドの完全な柔軟性を考慮した設計
Cluster Autoscalerではインスタンスタイプ、ゾーン、さらにインスタンスの購入オプション(スポットだとかリザーブドだとかそういうやつ)など様々なニーズを考慮した設計になっていないため、Karpenterはそうしたクラウドの柔軟な選択肢に対応したソフトウェアになっているらしいです。
グルーピングに依存しないノード管理
上記の通り、EKSのCluster Autoscalerは良くも悪くもASGに張り付きの設計になっています。自動ディスカバリができるようになって便利にはなったものの、ノードグループを複数作ったり管理したりするのは大変でもあります。
Karpenterを使うことによって、必要なときに必要なリソースを必要なだけ割り当てる「クラウドらしい体験」を与えられるようになるのはシンプルに便利そうです。
実際に挙動を確認したところ違いそうではありましたが、GKEでいうとNAP(Node Auto Provisioning)のような何かと言ってもよさそうです。
スケジュールの速やかな実施
Cluster Autoscalerは良くも悪くも「ノードがもっとほしいので増やす/ノードが余っているので減らす」までしか見ないため、あるPodがPendingになっているときにそのPodをスケジュールするのはkube-schedulerが担当していました。ノードが立ち上がってからReadyになるまで発火しないので、スケジューリングまでに若干ラグがあったのです。
Karpenterの場合はノードが作成されると同時にPodの割当が発生し、ノード上のKubeletは速やかにそのPodを起動させることができるようになります。ピタゴラスイッチの手間が大きく省けるので全体として素早いスケーリングが可能になっているようです。
挙動を確認してみた
Karpenterのクイックスタートをやってみたところ、以下のようにノードグループにいないノードがEKS上に登録されました。EC2ダッシュボードを見るとノードは存在しているのですが、EKS側ではそのノードは少なくともノードグループにはいないことになります。
うわなにこれキモいKarpenter pic.twitter.com/E67AX2MhNa
— inductor (@_inductor_) December 6, 2021
一旦挙動を確認するところまでで今日は終わりにしますが、次の投稿ではもう少し実装の中身にも触れる予定です。