FleetとKubernetesを100万クラスターにスケーリング

FleetとKubernetesを100万クラスターにスケーリング

Darren Shepherd
Darren Shepherd
Published: November 11, 2020
Updated: November 24, 2020

私たちは、多数のKubernetesクラスタのGitOpsスタイルの集中管理を提供したく、Fleet Projectを立ち上げました。Fleetの重要な設計目標は、100万台の地理的に分散したクラスタを管理できるようにすることです。Fleetを設計したとき、私たちは標準的なKubernetesコントローラアーキテクチャを使用したいと考えていました。これは、スケールするためには、これまでよりもはるかに遠くまでKubernetesをスケールできることを証明する必要があることを意味していました。本ブログでは、Fleetのアーキテクチャ、スケールをテストするために使用した方法、そしてその結果を紹介します。

なぜ100万?

K3sの需要が飛躍的に高まっているのと同様に、Kubernetesもエッジでの利用が増えています。組織は、各デバイスがシングルノードクラスタであるエッジデプロイモデルを採用しています。あるいは、高可用性(HA)を提供するために3ノードクラスタを見かけることもあるかもしれません。重要なのは、多くのノードを持つ単一の大規模なクラスタではなく、多くの小さなクラスタを扱うということです。今日、Linuxを実行している人の多くは、ワークロードを管理するためにKubernetesを使用しようとしています。ほとんどのK3sエッジデプロイメントは10,000ノード未満ですが、100万ノードに達することも不合理ではありません。最も重要なの点は、Fleetがあなたのスケール要件を満たしてくれるということです。

Fleetアーキテクチャ

Fleetのアーキテクチャの主要部分は以下の通りです。

  1. Fleetは2段階プル方式を採用しています。
  2. Fleetは標準のK8s APIインタフェースによって駆動されるK8sコントローラのセットです。
  3. Fleetエージェントは常時接続されている必要はありません。
  4. Fleetエージェント自体はKubernetesコントローラの別のセットです。

git からデプロイを行うには、Fleet Manager はまず git の内容をクローンして保存します。そして、Fleet Manager は、どのクラスタを git の内容で更新する必要があるかを判断し、エージェントが読むことができるようにデプロイメントレコードを作成します。エージェントが読めるようになったら、エージェントがチェックインしてデプロイメントレコードを読み、新しいアセットをデプロイして、状況を報告します。

Image

スケールテスト方法

100万クラスタをシミュレーションするために、2つのアプローチを使用しました。まず、大規模なVM(m5ad.24xlarge - 384GiB RAM)のセットをデプロイしました。各 VM は k3d を使用して 10 個の K3s クラスタを実行しました。そして、これらの10個のK3sクラスタは750個のエージェントをそれぞれ実行し、各エージェントは下流のクラスタを表しました。合計で、各 VM は 7,500 個のクラスタをシミュレートしました。平均して、VMをデプロイし、すべてのクラスタをFleetに登録してから定常状態になるまでに約40分かかりました。2日間かけて、10万クラスタに達するまで、このような方法でVMを起動しました。最初の10万クラスタの間に、スケーリングの問題の大部分を発見しました。これらの問題を修正した後、スケーリングはかなり予測可能なものになりました。このペースでは、900,000クラスタをシミュレートするには長時間がかかるうえ、費用も必要になります。

それは、下流のKubernetesクラスタやKubernetesリソースのデプロイを必要とせずに、100万台のクラスタが行うすべてのAPIコールを行うことができる単一のシミュレータを実行するというものです。その代わりに、シミュレータは新しいクラスタを登録し、新しいデプロイを発見し、成功したステータスを報告するためのAPIコールを行いました。このアプローチを使用して、1日でゼロから100万個のシミュレートされたクラスタを実現しました。

Fleet Managerは、Kubernetesクラスタ上で動作するコントローラで、3つの大規模VM(m5ad.24xlarge - 384 GiB RAM)とRDS(db.m5.24xlarge)インスタンス上で動作します。私たちは実際にK3sを使用してFleet Managerクラスタを実行しました。これを行ったのは、Kineがすでに統合されていたからです。なぜKineを使用したのか、それが何なのかは後程ご説明します。K3sは小規模なクラスタをターゲットにしているとはいえ、大規模なスケールで動かすにはおそらくKubernetesディストリビューションの中で最も簡単なものであり、その容易さから使用しました。EKSのようなマネージドプロバイダでやっていたような規模でFleetを動かすことはできませんので、そちらも後程ご説明します。

考察結果: サービスアカウントの調整とレート制限

最初にぶつかった問題は、まったく予想外のものでした。FleetエージェントがFleet Managerに登録するとき、それは一時的なクラスタ登録トークンを使ってそれを行います。その後、そのトークンは、そのクラスタ/エージェントのための新しいIDとクレデンシャルを作成するために使用されます。クラスタ登録トークンとそのエージェントのクレデンシャルの両方がサービス・アカウントです。クラスタを登録できる速度は、コントローラマネージャがサービスアカウント用のトークンを作成できる速度によって制限されていました。調査の結果、コントローラマネージャのデフォルト設定を変更して、サービスアカウントの作成速度(–concurrent-serviceaccount-token-syncs=100)と、1秒あたりの全体的なAPIリクエスト数(–kube-api-qps=10000)を増加させることができることがわかりました。

考察: etcdはこの規模では動作しない

FleetはKubernetesのコントローラとして書かれています。そのため、Fleetを100万クラスタにスケーリングすることは、Kubernetesで数千万のオブジェクトを管理することを意味していました。私たちは、Etcdではその量のデータを管理することができないことを知っていました。etcdのキースペースの制限は8GBで、デフォルトでは2GBに設定されています。キースペースには、現在の値と、ガベージコレクションされていないその前の値が含まれています。Fleetでの単純なクラスタオブジェクトは約6KBを必要とします。100万個のクラスタの場合、最低でも6GBは必要になります。しかし、1つのクラスタは通常、約10個のKubernetesオブジェクトに加えて、デプロイメントごとに1つのオブジェクトが必要です。つまり、実際には100万クラスタの場合、10倍以上のスペースが必要になる可能性が高いということです。

etcdの制限を回避するために、従来のRDBMSを使用して任意のKubernetesディストリビューションを実行できるようにするKineを使用しました。このスケールテストでは、RDS db.m5.24xlargeインスタンスを実行しました。データベースの適切なサイジングは行わず、代わりに最大のm5インスタンスから始めました。テスト終了時には、Kineには約2,000万個のオブジェクトがありました。これは、Fleetをこの規模で実行するには、EKSのようなマネージドプロバイダでは実行できないことを意味しています。

このテストでは、データベースをあまり強くプッシュしていないように見えます。確かに、私たちは非常に大きなデータベースを使用しましたが、垂直方向のスケーリングの余地がたくさん残っていることは明らかです。1つのレコードの挿入とルックアップは、許容範囲内の速度で実行を継続しました。一点気づいたことは、オブジェクトの大規模なリスト(最大でも10,000個)をランダムに検索するのに30秒から1分かかるということでした。一般的に、これらのクエリは1秒未満、または非常に乱暴なテストでは5秒で完了します。非常に長いクエリは、後述するキャッシュのリロード中に発生したため、システム全体への影響はほとんどありませんでした。これらの遅いクエリが Fleet に大きな影響を与えているわけではないのに、なぜこのような現象が起こったのかをさらに調査する必要があります。

考察: Watch Cache Sizeを大きくする

コントローラがキャッシュをロードすると、まずすべてのオブジェクトをリストアップし、リストのリビジョンからウォッチを開始します。変更率が非常に高く、リストの作成に時間がかかる場合、APIサーバーのウォッチキャッシュにリビジョンが存在しないか、またはetcdでコンパクト化されているため、リストは終了したがウォッチを開始できないという状況に陥りやすくなります。回避策として、Watch Casheの量を非常に多く設定しました(–default-watch-cache-size=10000000)。理論的には、Kineでコンパクションの問題にぶつかると思っていたのですが、そうではありませんでした。これはさらなる調査が必要です。一般的に、Kine はコンパクト化の頻度にはあまり積極的ではありません。しかし、この状況では、Kine が圧縮するよりも早くレコードを追加していたのではないかと疑われます。これはそれほど悪いことではありません。私たちが押していた変更率が一貫しているとは考えていません–それは、私たちが速いペースでクラスターを登録していたからに他なりません。

考察: ロードが遅いキャッシュ

Kubernetesコントローラの標準的な実装は、作業中のオブジェクトをすべてメモリにキャッシュすることです。Fleetの場合は、キャッシュを構築するために何百万ものオブジェクトをロードする必要があることを意味します。オブジェクトのリストは、デフォルトのページネーションサイズが500になっています。100万個のオブジェクトをロードするのに2,000回のAPIリクエストが必要です。リストコールを行い、オブジェクトを処理し、1秒ごとに次のページを開始できると仮定すると、キャッシュをロードするのに約30分かかることになります。残念ながら、2,000回のAPIリクエストのどれかが失敗すると、処理がやり直しになってしまいます。ページサイズを10,000オブジェクトまで増やしてみましたが、全体的なロード時間は大幅に速くならないことがわかりました。一度に10,000個のオブジェクトをリストアップし始めると、Kineがすべてのオブジェクトを返すのにランダムに1分以上かかるという問題に遭遇しました。その後、Kubernetes API サーバーがリクエストをキャンセルして、全体のロード操作が失敗して再起動しなければならないという問題が発生しました。この問題はAPIリクエストのタイムアウトを増やす(–request-timeout=30m)ことで回避しましたが、これは許容できる解決策ではありません。ページサイズを小さくしておけばリクエストの高速化は確実ですが、リクエストの数が多いと1つのリクエストが失敗して処理全体が再起動される可能性が高くなります。

Fleetコントローラの再起動には最大 45 分かかります。この再起動時間は、kube-apiserver と kube-controller-manager にも適用されます。つまり、サービスの再起動方法には細心の注意が必要です。この点は、K3sを実行しても、RKEのような従来のディストリビューションを実行するのと比較して、あまり良くないことがわかりました。K3s は api-server と controller-manager を同じプロセスに統合しているため、api-server や controller-manager の再起動が本来あるべき姿よりも遅く、エラーが発生しやすくなっています。Kubernetes を含むすべてのサービスの完全な再起動を必要とする、より破局的な障害をシミュレートすると、オンラインに戻すのに数時間かかりました。

キャッシュのロードにかかる時間と障害の可能性は、Fleetのスケーリングで発見した最大の問題です。今後、これが私たちが対処したい第一の課題です。

まとめ

私たちのテストでは、Fleetのアーキテクチャが100万クラスタまでスケールすること、さらに重要な点は、Kubernetesをプラットフォームとして利用してかなり多くのデータを管理できることを証明しました。Fleet自体はコンテナとは直接関係なく、Kubernetesでデータを管理するシンプルなアプリケーションに過ぎないと見ることができます。これらの発見は、Kubernetesをコードを書くための汎用的なオーケストレーションプラットフォームとして扱うことの可能性を大きく広げている。コントローラのセットをK3で簡単にバンドルできることを考えると、Kubernetesは自己完結型のアプリケーションサーバになります。

大規模な場合、キャッシュのリロードにかかる時間は気になりますが、間違いなく管理可能です。私たちは、100万台のクラスタを実行することが可能なだけでなく、シンプルなものになるように、この分野で改善を続けていきます。Rancher Labsはシンプルなものを愛しています。

Darren Shepherd
Darren Shepherd
共同創業者兼最高技術責任者
Rancher入社前はCitrixでシニア・プリンシパル・エンジニアとして、CloudStack、OpenStack、Docker、次世代のインフラストラクチャ・オーケストレーション技術の構築に携わっていました。Citrix入社前は、GoDaddyに勤務し、パブリックおよびプライベートIaaSクラウドの両方を実装するチームを設計、指揮していました。DARRENは 10 歳のときに初めて286を手にして以来、ソフトウェアを書き続けてきました。クローゼットに閉じこもり、Java以外のものを叩いているときが一番幸せです。Darrenは、完全に信頼できないシステムを確実にコントロールするシステム構築が専門。Darrenは、カリフォルニア州立大学ノースリッジ校で学士号を取得しています。
Rancherを始めましょう