eBPFとサービスメッシュ
日付:2021/12/08
関連プロダクト:Cilium
日付:2022/06/07
関連プロダクト:Linkerd
How eBPF will solve Service Mesh – Goodbye Sidecars
What is Service Mesh?
現在、サービス メッシュは一般的に、サイドカー モデルと呼ばれるアーキテクチャを使用して実装されています。このアーキテクチャは、上記の機能(回復力のある接続、ID ベースのセキュリティ、可観測性と追跡、透明性)を実装するコードをレイヤ 4 プロキシにカプセル化し、サービスとの間のトラフィックに依存して、このいわゆるサイドカー プロキシにリダイレクトされます。バイクにサイドカーが取り付けられているように、各アプリケーションにプロキシが取り付けられているため、サイドカーと呼ばれます。
このアーキテクチャの利点は、サービスがサービス メッシュ機能自体を実装する必要がなくなったことです。これは、さまざまな言語で記述された多くのサービスが展開されている場合、または不変のサードパーティ アプリケーションを実行している場合に役立ちます。
このモデルの欠点は、膨大な数のプロキシ、多くの追加のネットワーク接続、およびネットワーク トラフィックをプロキシに供給するための複雑なリダイレクト ロジックです。さらに、レイヤ 4 プロキシにリダイレクトできるネットワーク トラフィックの種類にも制限があります。プロキシがサポートできるネットワーク プロトコルは限られています。
サイドカープロキシがレイヤ4と書いているが、レイヤ7のプロキシを採用しているサービスメッシュが大半ではないか?
Extending the Kernel Namespace Concept
現在、最適な透明性、効率性、およびセキュリティのために、オペレーティング システムでこれをネイティブにサポートすることが理にかなっています。
当然のことながら、これは非常に自然に見え、おそらくほとんどのユーザーがシンプルさの観点から期待するものです.アプリケーションは変更されず、これまでどおりソケットを使用して通信を続けます。望ましいサービス メッシュ機能は、Linux の一部として透過的に提供されます。 TCP が今日そこにあるように、それはまさにそこにあります。
Unlocking the Kernel Service Mesh with eBPF
eBPF はこの式を変更します。 Linux カーネルの機能を動的に拡張できます。私たちは Cilium に eBPF を使用して、Linux カーネルに直接組み込まれる非常に効率的なネットワーク、セキュリティ、可観測性のデータパスを構築してきました。これと同じ概念を適用して、サービス メッシュの要件をカーネル レベルでも解決できます。実際、Cilium は、ID ベースのセキュリティ、L3-L7 の可観測性と承認、暗号化、負荷分散など、必要なさまざまな概念を既に実装しています。欠落している部分は現在、Cilium に来ています。このブログの最後に、Cilium コミュニティが主導する Cilium サービス メッシュ ベータ プログラムに参加する方法の詳細が記載されています。
eBPF Accelerated Per-Node Proxy
この eBPF のみのアプローチでカバーできるユースケースがますます増えているため、L4 プロキシを完全に無効にできます。一部のユース ケースでは、プロキシが引き続き必要です。たとえば、接続をスプライシングする必要がある場合、TLS ターミネーションが実行されている場合、または何らかの形式の HTTP 認証のために使用されます。
Sidecar vs per-Node Proxy
Proxies per Connection
サイドカー モデルで同じ機能を提供するには、プロキシを接続に 2 回挿入する必要があり、その結果、3 つの接続を維持する必要があります。これにより、オーバーヘッドが増加し、すべての追加ソケット バッファに必要なメモリが倍増し、サービス間の待ち時間が長くなります。これは、サイドカーのない L7 可視性のセクションで前に見たサイドカーのオーバーヘッドです。
ノードごとのプロキシ モデルに切り替えると、各ワークロード内でサイドカーを実行することに依存しなくなるため、プロキシの 1 つを取り除くことができます。追加の接続を必要としないよりはまだ理想的ではありませんが、常に 2 つの追加の接続を必要とするよりはましです。
Total number of proxies required
各ワークロードでサイドカーを実行すると、多数のプロキシが発生する可能性があります。個々のプロキシ インスタンスのメモリ フットプリントがかなり最適化されている場合でも、インスタンスの数が非常に多いため、全体的な影響が大きくなります。さらに、各プロキシは、ルーティングやエンドポイント テーブルなどのデータ構造を維持し、クラスターの成長に合わせて大きくなります。そのため、プロキシーごとのメモリ消費量は、クラスターが大きくなるほど高くなります。現在、一部のサービス メッシュは、部分的なルーティング テーブルを個々のプロキシにプッシュし、ルーティング先を制限することで、これを解決しようとしています。
500 ノードのクラスターで 30 ポッド/ノードを想定すると、サイドカー ベースのアーキテクチャでは 15,000 のプロキシを実行する必要があります。プロキシごとに 70MB のメモリが消費されるため (高度に最適化されたルーティング テーブルを既に想定しています)、それでもクラスター内のすべてのサイドカーによって 1.5TB のメモリが消費されます。ノードごとのモデルでは、プロキシごとに想定される同じメモリ フットプリントで、500 個のプロキシが 34GB を超えるメモリを消費しません。
Multi-Tenancy
サイドカー モデルからノードごとのモデルに移行すると、プロキシは複数のアプリケーションの接続を提供します。プロキシはマルチテナント対応にする必要があります。これは、個々の仮想マシンの使用からコンテナーの使用に切り替えたときに発生したのとまったく同じ移行です。各仮想マシンで実行するオペレーティング システムの完全に個別のコピーを使用するのをやめ、オペレーティング システムを複数のアプリケーションと共有するようになったため、Linux はマルチテナントに対応する必要があります。これが、名前空間と cgroup が存在する理由です。それらがなければ、単一のコンテナーがシステムのすべてのリソースを消費し、コンテナーが制御されていない方法で互いのファイルシステムにアクセスする可能性があります。
「まったく同じ移行です」そうか?
これがサービス メッシュ レベルでネットワーク リソースに対してまったく同じように動作するとしたら、すばらしいと思いませんか? Envoy には名前空間の初期概念が既にあり、それらはリスナーと呼ばれます。リスナーは、個別の構成を保持し、独立して動作できます。これにより、まったく新しい可能性が開かれます。突然、リソースの消費を簡単に制御し、公平なキューイング ルールを確立し、利用可能なリソースをすべてのアプリケーションに均等に、または指定されたルールに従って配布できるようになります。これは、今日の Kubernetes でアプリケーションの CPU とメモリの制約を定義する方法とまったく同じように見える可能性があり、そうあるべきです。このトピックについて詳しく知りたい場合は、EnvoyCon で話しました (Envoy Namespaces – Operating an Envoy-based Service Mesh at a Fraction of the Cost、Thomas Graf、EnvoyCon 2019)。
/icons/hr.icon
eBPF, sidecars, and the future of the service mesh
しかし、eBPF はどれほど強力なネットワーク技術なのでしょうか?たとえば、Linkerd のサイドカー プロキシを完全に置き換えて、すべてをカーネル内で行うことができるでしょうか?
この記事では、特にユーザーへの影響に関して、この可能性を評価するために最善を尽くします。 eBPF とは何か、できることとできないことについて説明します。サイドカーと他のモデルを掘り下げ、運用とセキュリティの観点から比較します。最後に、Linkerd チームが eBPF に関連するサービス メッシュの将来について考えていることについて、私の結論を述べます。
What is eBPF?
アプリケーションでネットワーク パケットを処理するとします。 ホスト マシンのネットワーク バッファに直接アクセスすることはできません。 このバッファはカーネルによって管理され、カーネルはそれを保護する必要があります。たとえば、あるプロセスが別のプロセスのネットワーク パケットを読み取れないようにする必要があります。 代わりに、アプリケーションは、本質的にカーネル API 呼び出しである syscall を介してネットワーク パケット情報を要求できます。 もしそうなら、それをあなたに返します。
syscall は移植可能であり、コードは Linux 以外のマシンでも動作しますが、低速です。 マシンが 1 秒あたり数千万のパケットを処理する可能性がある最新のネットワーク環境では、syscall ベースのコードを記述してすべてのパケットに対して何かを行うことは受け入れられません。
eBPF を入力します。 コードが「カーネル空間」と「ユーザー空間」の間を行ったり来たりするタイトなループで syscall を呼び出すのではなく、代わりにコードをカーネルに直接渡して、それ自体を実行するように指示します。 出来上がり: syscall はもう必要ありません。アプリケーションはフルスピードで実行できます。 (もちろん、以下で説明するように、これほど単純ではありません。)
eBPF は大きな進歩ですが、特効薬ではありません。 任意のアプリケーションを eBPF として実行することはできません。 実際、eBPF でできることは非常に限られていますが、それには十分な理由があります。
Contended multi-tenancy is hard
eBPF が非常に制限されている理由を理解する前に、カーネル自体が非常に制限されている理由について説明する必要があります。 システムコールのようなものが存在するのはなぜですか? プログラムがネットワーク (またはメモリ、またはディスク) に直接アクセスできないのはなぜですか?
カーネルは、競合するマルチテナンシーの世界で動作します。 マルチテナンシーとは、複数の「テナント」 (人、アカウント、その他の形式のアクターなど) がマシンを共有し、それぞれが独自のプログラムを実行することを意味します。 競合しているということは、これらのテナントが友達ではないことを意味します。 お互いのデータにアクセスしたり、干渉したりしてはなりません。 カーネルは、任意のプログラムの実行を許可しながら、その動作を強制する必要があります。 つまり、カーネルはテナントを分離する必要があります。
これは、カーネルが、実行するように指示されたプログラムを本当に信頼できないことを意味します。 あるテナントのプログラムが、別のテナントのデータまたはプログラムに何か悪いことをしようとする可能性はいつでもあります。 カーネルは、明示的な許可が与えられていない限り、他のプログラムを停止または中断したり、リソースを拒否したり、実行する機能を妨害したり、メモリ、ネットワーク、またはディスクからデータを読み取ったりできないようにする必要があります。
これは重要な要件です。 世界中のほぼすべてのソフトウェア関連のセキュリティ保証は、最終的には、これらの種類の保護を実施するカーネルの能力に帰着します。 別のプログラムのメモリやネットワーク トラフィックを許可なく読み取ることができるプログラムは、データの流出、またはさらに悪いことへの道です。 別のプログラムのメモリまたはネットワーク トラフィックを書き込むことができるプログラムは、詐欺の手段であり、さらに悪いことです。 プログラムがルールを破ることを可能にするカーネルのエクスプロイトは、非常に大きな問題です。 そして、これらの規則を破る最善の方法の 1 つは、カーネルの内部状態にアクセスすることです。カーネル メモリの読み取りまたは書き込みができれば、規則を回避できます。
そのため、アプリケーションとカーネル間のすべてのやり取りが非常に精査されています。 失敗の結果は非常に高くなります。 カーネル開発者は、この問題に何千年もの努力を注ぎ込んできました。
これが、コンテナーが非常に強力な理由でもあります。コンテナーは、これらと同じ分離保証を採用し、アプリケーションと依存関係の任意のパッケージに適用します。 比較的新しいカーネル マジックのおかげで、競合するマルチテナンシーを処理するカーネルの機能を最大限に活用して、コンテナーを互いに分離して実行できます。 仮想マシンを使用してこの分離を実現する以前の方法は、時間とコストがかかりました。 コンテナーの魔法は、劇的に安価な方法で同じ保証を (ほとんど) 提供してくれることです。
私たちが「クラウド ネイティブ」と考えるもののほぼすべての側面は、これらの分離の保証に依存しています。
eBPF is limited
eBPFに戻ります。 説明したように、eBPF を使用すると、カーネル コードを渡して、「これをカーネルで実行してください」と言うことができます。 カーネル セキュリティの観点からは、これが非常に恐ろしいことであることがわかっています。アプリケーションとカーネルの間のすべての障壁 (syscall など) をバイパスし、セキュリティの悪用領域に直接陥ることになります。
したがって、これを安全にするために、カーネルは実行するコードにいくつかの非常に重要な制約を課します。 それらを実行する前に、すべての eBPF プログラムはベリファイアを通過する必要があります。これにより、不正な動作がチェックされます。 検証者がプログラムを拒否すると、カーネルはそのプログラムを実行しません。
プログラムの自動検証は困難であり、検証者は過度に制限する側で過ちを犯さなければなりません。 したがって、eBPF プログラムは非常に限られています。 たとえば、ブロックすることはできません。 制限のないループを持つことはできません。 また、定義済みのサイズを超えることはできません。 また、複雑さにも制限があります。ベリファイアは考えられるすべての実行パスを評価し、ある制限内で完了できない場合、またはすべてのループに終了条件があることを証明できない場合、プログラムはパスしません。
これらの制約に違反する完全に安全なプログラムはたくさんあります。 これらのプログラムの 1 つを eBPF として実行したい場合は、残念です! ベリファイアを満足させるには、それを書き直す必要があります。1 eBPF のファンにとって朗報は、カーネルのリリースごとにベリファイアが賢くなるにつれて、これらの制限が徐々に緩和されることです。 これらの制限を回避する創造的な方法もいくつかあります。
しかし、これにもかかわらず、eBPF がどのように制約されるか (モデルが機能するためには制約されなければならない) の性質は、eBPF プログラムが実行できることが非常に限られていることを意味します。 複数のパケットにわたるデータのバッファリングでさえ、eBPF では自明ではありません。 HTTP/2 トラフィックの例の全範囲を処理するために必要な種類の重大な処理は、純粋な eBPF の範囲をはるかに超えており、TLS 化されたデータを終了することは不可能です。
せいぜい、eBPF はこの作業のほんの一部しか実行できず、ユーザー空間アプリケーションを呼び出して、複雑すぎて eBPF で直接処理できない部分を処理します。
eBPF vs the service mesh
The eBPF service mesh still requires proxies
The future of the service mesh
すべてをまとめると、1 つの結論が残されます。eBPF を使用するか、eBPF を使用しないかにかかわらず、サービス メッシュの近い将来は、ユーザー空間で実行されるサイドカー プロキシから構築されます。
サイドカーには問題がないわけではありませんが、コンテナーによって提供される分離の保証を維持しながら、クラウド ネイティブ ネットワーキングの複雑さの全範囲を処理するための今日の最善の答えです。 また、eBPF がサービス メッシュから作業をオフロードできる範囲で、ホストごとのプロキシではなく、サイドカー プロキシを使用してそれを行う必要があります。 「コンテナ化の運用とセキュリティの利点を維持しながら、既存のサイドカーベースのアプローチをはるかに高速化する」は、「サイドカーを取り除くことでサービス メッシュの複雑さとパフォーマンスを解決する」と同じマーケティングリングを持っているわけではありませんが、ユーザーの観点からは、 それは勝利です。
eBPF の機能は、最終的に、サービス メッシュによって提供される L7 作業の全範囲を処理するためにプロキシが必要ないところまで成長しますか? おそらくですが、上で概説した理由により、それでもユーザー空間のプロキシを放棄することが理にかなっている可能性は低いです。 カーネルは、他のメカニズムを通じてサービス メッシュ作業の全範囲を吸収できますか? おそらくですが、今日では「サービス メッシュ カーネル モジュール」に対する需要はほとんどなく、何がそれを魅力的なものにするのかは不明です。
そのため、近い将来、Linkerd プロジェクトはサイドカー マイクロ プロキシをできる限り小さく、高速で、運用上無視できるものにするための努力を続けます。 私たちの基本的な義務は、ユーザーと Linkerd の運用経験に対するものであり、そのレンズを通して、すべての設計とエンジニアリングのトレードオフを常に測定する必要があります。