Carettaで本番環境の幸せな航海へ
Carettaを知ってください - あなたのクラスターで動いているサービスの視覚的なネットワークマップを即座に作成する軽量でスタンドアローンなツールです。CarettaはeBPFを活用してK8sクラスター内のサービスネットワークの相互作用を効率的にマッピングし、収集したデータをクエリして視覚化するためにGrafanaを使用します。
もともとはgroundcoverのブログにUdi Rot(創業エンジニア)によって投稿されたものです
科学者たちは長い間、カメのような多くの動物が、船乗りが緯度と経度を使うのと同じように、磁場の目に見えない線を感じ取って海を航行することを知ってきました。
しかし、普通のウミガメはそれ以上のことをします。ウミガメは地球の磁場を使って自分が生まれた海岸線の独特な磁気のシグネチャーを内部コンパスとして活用し、帰路を見つけます。
ウミガメは効果的に広大な海の荒野を手懐けています。一部の動物にとっては無限の未知のものと見なされるものが、ウミガメの頭の中では細部にわたってマッピングされています。
海からクラウドへ、典型的なKubernetesクラスターで道に迷うのは非常に簡単です。クラスター内で実行されているさまざまなワークロード間の相互依存関係を適切に理解することは複雑な作業であり、チームは重要なアクション可能なインサイト、例えば失敗の中心点の特定やセキュリティの異常の特定などを得るために懸命に作業しなければなりません。
この課題に取り組む1つのアプローチは視覚化です:多くの点で、K8sクラスターは地理的エリアと見なすことができ、異なるワークロード間の通信によって形作られた道と小道を持っています。そして、地図があなたの近所を知り、それをナビゲートする方法を知るのに役立つのと同じように、あなたのK8sクラスターを「回る」のに役立つことができます。
これはクラウドネイティブの監視ツールの使命の一部です - APM製品は何らかの形でネットワークトレース機能なしでは完全ではありません、そしてこれらのトレースからのデータは前述のような質問に答えるのに役立つかもしれません。しかし、私たちが以前の投稿であるMurreからのアプローチを続けるとしたら、もし私が最小限の、効率的なソリューションだけが欲しいとしたらどうでしょうか。
それでは、私たちのクラスターをマップする最も簡単な方法はなんでしょうか?
Carettaの紹介 - まさにそれを実行するスタンドアローンのOSSツールです。それがどのように機能するか、eBPFテクノロジーを活用して軽量でフリクションレスにする方法、そしてそれを構築する過程で遭遇した障害物と挑戦について見ていきましょう。最終結果は生のPrometheusメトリックとして直接消化することも、いくつかの事前に作成されたパネルをGrafanaに統合することもできます:
[画像]
土地の探索
最初に必要なことは、ネットワークデータをどのように取得するかを把握することです。単純なアプローチは、_tcpdump_のようなスニッフィングツールを使用してネットワークの観測可能性を得ることです。しかし、それは過剰かもしれません - 実際にネットワークトラフィックをキャプチャする必要はありません、私たちはそれが存在することを知りたいだけです。上述のように、私たちは必要なデータだけをプローブするためにeBPFを使用することができます。
eBPFとは?
もしまだeBPFのことを聞いたことがなければ、人々はそれを「貴重なテクノロジー」と呼び、JavaScriptに例えることができます:
静的なHTMLウェブサイトの代わりに、JavaScriptはマウスクリックのようなイベントで実行されるミニプログラムを定義することを可能にし、それはブラウザ内の安全な仮想マシンで実行されます。そしてeBPFでは、固定されたカーネルの代わりに、ディスクI/Oのようなイベントで実行されるミニプログラムを書くことができるようになり、それらはカーネル内の安全な仮想マシンで実行されます。
eBPFは2014年初頭に導入され、BPFの元のアーキテクチャを拡張して、複雑なプログラムを直接Linuxカーネル空間で実行するツールを提供しました。
OK、おそらく今あなたはカーネルのスペースで実行するというのがどういう意味なのか自問しているでしょう。要するに、それは標準アプリケーションのような「ユーザースペース」で実行されるのとは対照的に、より高い権限でコードを実行するということです。それはコードを非常に効率的に実行させることを可能にし、それ以外ではユーザースペースからアクセスするには複雑でコストがかかる低レベルのカーネルリソースにアクセスすることを可能にしますが、最も重要なのは:それはユーザースペースで実行されている全てのプログラムを観察することを可能にすることであり、これはユーザースペースで動作する監視ツールに依存する場合に困難です。
これは大きなことです。それは基本的にプログラマブルで非常に効率的な仮想マシンを備えたLinuxカーネルにアクセスする新しい方法であり、プログラマーは以前はカーネル開発者の専売特許であったものにアクセスすることができます。
監視はeBPFが引き立つ領域です。それは、開発チームがコードの変更やR&Dの努力をゼロで実行中のアプリケーションを監視する完全に追跡対象外のアプローチを可能にします。 eBPFは高精度なデータを収集するためのより高速でリソース集約度が低い総合的なアプローチという、監視アプリケーションにとって強力な利点を提供します。
eBPFは実行中のシステムからデータをキャプチャする多くの方法を提供します。カーネルは、開発者がeBPFを使用することを可能にし、彼らのプログラムを様々なタイプのプローブにアタッチすることを許可しています - コードのカーネルまたはアプリケーションの中のプローブされる所に到達したとき、元のコードを実行する前か後にそれらにアタッチされたプログラムを実行する場所です。この図はeBPFに利用可能なプローブのいくつかを示しています:
[画像]
ebpf.io/what-is-ebpfからの画像
基本から始めます
このプロジェクトに取り組むにあたり、私はtcplifeにインスパイアされました - 単一のeBPFプローブを使用してTCPの寿命の統計と情報を計算する巧妙なツールです。実際、カーネルは私たちのために半分の仕事をすでに行っており、それは各ソケットに対して、例えばスループットのような情報を保持しています。_tcp_set_state_カーネル関数をプローブすることにより、_tcplife_はアクティブなネットワーク接続を認識し、それらのデータにアクセスできます。最小のフットプリントを持つことに加えて、特定のカーネル機能をプローブするという別の利点は、アプリケーションが使用する可能性のある、read()やrecv()などの多くの可能性のあるシスコールをプローブするよりも、すべての可能なデータフローをカバーすることです。アプリケーションレベルのコンテキストが不要な場合、「ツリーの根元」に密着して座ることが分枝をより簡単にカバーすることを可能にします。
素晴らしいように聞こえます - しかし、私たちはまだ何かを逃しているでしょう。_tcp_set_state_は、当然ながらTCP接続の状態が設定されているときに呼ばれます。例えば、サーバーが待ち受けを開始したとき、またはサーバー・クライアント接続が確立されたとき、または接続が閉じられたときなどです。しかし、TCP接続は長い間その状態を変えずに続けることができ、_tcp_set_state_に依存することは私たちをそれらに盲目にしてしまいます。
私たちは写真を完成させることができる追加のプローブを探しに出かけました。それでも、私たちはLinux TCPスタックを探索するためにeBPFを有用と見つけました。stacksnoopやstackcountのようなツールは、ネットワークパケットが処理されるときにどのフローを通過するのか、および異なる機能を比較して各機能がどれだけ「騒々しい」かを理解するために使用することができます。データプロービングの場所を探すことは、あまりにも騒々しいか盲目的かという間の絶え間ないトレードオフを含みますが、私たちは真ん中の甘い所を探しています。
[画像]
私たちの場合、tcp_data_queue関数は私たちのニーズに適していることがわかりました:
[画像]
この関数はtcp_rcv_establishedの最終ステップの1つとして呼ばれます。これはESTABLISHED状態でパケットを受信するときに使用される関数です:
[画像]
それで、_tcp_set_state_の盲点をカバーし、すべての前のステップが成功した場合にのみ呼ばれます。
この関数を使用するもう1つの利点は、それが_tcp_set_state_と同様に、そしてカーネルTCP関数のほとんどは、その第一引数がstruct sockオブジェクトであるということです。これは大きな重要なカーネルのstructであり、データを取得するためにそれに依存する利点と欠点にすぐに飛び込みますが、今のところ私たちは両方のプローブがデータへの一貫したアプローチを共有していることを便利だと言っておきましょう。
データ収集メカニズムを要約すると - 我々は_tcp_data_queueをプローブして、その統計を更新しながらネットワークソケットを観察し、_tcp_set_state_をプローブしてそのライフサイクルを追跡します。
データを理解する
言及されたように、私たちの「データ供給」はsockと呼ばれる構造体のカーネル内ネットワークスタックオブジェクトから来ます。実はSocksは他のTCPとINETのデータ構造をラッピングしているので、それらを持つことは接続の下位レベルのデータも持っているということです。ソースIP、ソースポート、宛先IP、宛先ポートの接続の4タプルのような情報はsockから簡単に取得することができ、特にCO-REアプローチを使用することによってです。
カーネル内の構造体を使用することからいくつ
こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/shaharazulay/navigate-your-way-to-production-bliss-with-caretta-1clg