ByteDance オープンソース Kelemetry: Kubernetes コントロール プレーンのグローバル トラッキング システム

実践的な注意

82d6655c911b10587150615f4455aef3.gif

乾物が無くならない

Kelemetry は、Bytedance によって開発された Kubernetes コントロール プレーンの追跡システムであり、複数の Kubernetes コンポーネントの動作をグローバルな観点から接続し、単一の Kubernetes オブジェクトの完全なライフ サイクルと異なるオブジェクト間の相互作用を追跡します。K8s システム内のイベント チェーンを視覚化することで、Kubernetes システムの観察、理解、デバッグが容易になります。

db574c8c5b7af282a66ccf03918e7286.png

バックグラウンド

従来の分散トレースでは、「トレース」は通常、ユーザー要求中の内部呼び出しに対応します。特に、ユーザー要求が到着すると、トレースはルート スパンから開始され、その後、各内部 RPC 呼び出しによって新しい子スパンが開始されます。親スパンの期間は通常、その子スパンのスーパーセットであるため、トレースはツリーまたはフレーム グラフとして視覚的に視覚化でき、階層はコンポーネント間の依存関係を表します。

従来の RPC システムとは対照的に、Kubernetes API は非同期で宣言型です。アクションを実行するために、コンポーネントは API サーバー上のオブジェクトの仕様 (望ましい状態) を更新し、その後、他のコンポーネントが望ましい状態に到達するために自身を修正しようと継続的に試みます。たとえば、ReplicaSet のレプリカを 3 から 5 にスケールすると、spec.replicas フィールドを 5 に更新します。rs コントローラーはこの変更を監視し、合計数が 5 に達するまで新しいポッド オブジェクトを作成し続けます。kubelet は、管理するノードがポッドを作成したことを確認すると、ポッド内の仕様に一致するコンテナをそのノード上に生成します。

このプロセス中、rs コントローラーを直接呼び出すことはなく、rs コントローラーが kubelet を直接呼び出すこともありません。これは、コンポーネント間の直接の因果関係を観察できないことを意味します。プロセス中に元の 3 つのポッドのうちの 1 つが削除された場合、レプリカ セット コントローラーは 2 つの新しいポッドとともに別のポッドを作成します。この作成と ReplicaSet の拡張またはポッドの削除を相関させることはできません。したがって、「トレース」または「スパン」の定義が曖昧であるため、従来のスパンベースの分散トレーシング モデルは Kubernetes にはほとんど適用できません。

これまで、個々のコンポーネントは独自の内部トレースを実装していましたが、通常は「調整」ごとに 1 つのトレースでした (例: kubelet トレースは、単一のポッドの作成/更新を処理する同期操作のみをトレースします)。ただし、単一のトレースではプロセス全体を説明できず、ユーザー向けの動作の多くは複数の調整を観察することによってのみ理解できるため、可観測性が孤立してしまいます。たとえば、ReplicaSet を拡張するプロセスは、レプリカ セット コントローラー ReplicaSet の更新またはポッドの準備の更新を推測するための複数の調整。

可観測性データアイランドの問題を解決するために、Kelemetry は、コンポーネントに依存せず非侵入的な方法でさまざまなコンポーネントから信号を収集して接続し、関連データをトレースの形式で表示します。

デザイン

スパンとしてのオブジェクト

さまざまなコンポーネントからの可観測性データを接続するために、Kelemetry は kspan プロジェクトからインスピレーションを得た異なるアプローチを採用し、ルート スパンとして単一の操作を試みるのではなく、ここではオブジェクト自体に対してスパンが作成され、オブジェクトのそれぞれに対してスパンが作成されます。発生するイベントはすべてサブスパンです。さらに、個々のオブジェクトは、子オブジェクトのスパンが親の子スパンになるように、所有権によって相互にリンクされます。したがって、2 つの次元が得られます。ツリー階層はオブジェクト階層とイベント スコープを表し、タイムラインは多くの場合因果関係に沿ったイベントのシーケンスを表します。

たとえば、単一のポッド デプロイメントを作成する場合、監査ログとイベントのデータを使用して、デプロイメント コントローラー、rs コントローラー、および kubelet の間の相互作用を単一のトレースで表示できます。

32c6a1c96a7ea96904e77c05e3ca5141.png

トレースは通常、数秒続く短期間のリクエストをトレースするために使用されるため、トレース ストアの実装では、有効期間が長いトレースやスパンが多すぎるトレースはサポートされない可能性があります。スパンが多すぎるトレースは、一部のストレージ バックエンドでパフォーマンスの問題を引き起こす可能性があります。したがって、各イベントをそれが属する 30 分の時間枠に分割することで、各トレースの継続時間を 30 分に制限します。たとえば、12:56 に発生したイベントは、12:30 ~ 13:00 のオブジェクト スパンにグループ化されます。

分散 KV ストアを使用して、(クラスター、リソース タイプ、ネームスペース、名前、フィールド、30 分のタイムスタンプ) のマッピングを、対応するオブジェクト作成のトレース/スパン ID に保存し、オブジェクトごとにトレースが 1 つだけ作成されるようにします。

監査ログの収集

Kelemetry の主要なデータ ソースの 1 つは、apiserver の監査ログです。監査ログは、操作を開始したクライアント、関係するオブジェクト、リクエストの受信から完了までの正確な期間など、各コントローラー操作に関する豊富な情報を提供します。Kubernetes アーキテクチャでは、各オブジェクトへの変更により、関連付けられたコントローラーが調整され、その後のオブジェクトの変更が引き起こされるため、オブジェクトの変更に関連付けられた監査ログを観察することは、一連のイベントにおけるコントローラー間の対話を理解するのに役立ちます。

Kubernetes APIサーバーの監査ログは、ログ ファイルと Webhook という 2 つの異なる方法で公開されます。一部のクラウド プロバイダーは監査ログを収集する独自の方法を実装していますが、監査ログ収集の構成に対するベンダー中立的なアプローチについてはコミュニティでほとんど進歩がありません。自己提供クラスターの展開プロセスを簡素化するために、Kelemetry はネイティブ監査情報を受信するための監査 Webhook を提供し、ベンダー固有のメッセージ キューから監査ログを消費するためのプラグイン API も公開します。

イベント収集

Kubernetes コントローラーがオブジェクトを処理するとき、オブジェクトに関連付けられた「イベント」を発行します。これらのイベントは、ユーザーが kubectl description コマンドを実行すると表示され、多くの場合、コントローラーの動作についてわかりやすい説明が提供されます。たとえば、スケジューラーがポッドのスケジュールに失敗すると、詳細メッセージを含む FailToSchedulePod イベントが発行されます。

0/4022 ノードがポッド xxxxx の実行に使用可能です: 1072 メモリ不足、1819 CPU 不足、1930 ノードがノード セレクターと一致しません、71 ノードにポッドが許容できないテイント {xxxxx} がありました。

イベントは kubectl description コマンドで使用するために最適化されているため、各生のイベントは保持されず、代わりに最後に記録されたイベントのタイムスタンプとカウントが保存されます。一方、Kelemetry は、Kubernetes の Object List Observation API を使用してイベントを取得します。これは、イベント オブジェクトの最新バージョンのみを公開します。イベントの重複を避けるために、Kelemetry はいくつかのヒューリスティックを使用して、イベントをスパンとして報告する必要があるかどうかを「推測」します。

  • 最後に処理されたイベントのタイムスタンプを保持し、再起動後はそのタイムスタンプより前のイベントを無視します。イベントが受信される順序は必ずしも保証されませんが (クライアントのクロック スキュー、コントローラー-APIサーバー-etcd ラウンドトリップの一貫性のない遅延などのため)、この遅延は比較的小さく、コントローラーの再起動による重複のほとんどが除去されます。

  • 再リストによるイベントの重複を避けるために、イベントの resourceVersion が変更されていることを確認します。

オブジェクトの状態を監査ログと関連付けます

トラブルシューティングのために監査ログを調査するとき、特にさまざまなコンポーネントのセマンティクスが明確でない場合、「誰がこのリクエストを行ったか」ではなく、「このリクエストで何が変更されたか」を知ることに最も関心があります。Kelemetry は、オブジェクトの作成、更新、削除イベントを監視し、受信した監査イベントを監査スパンに関連付けるコントローラーを実行します。Kubernetes オブジェクトが更新されると、その resourceVersion フィールドが新しい一意の値で更新されます。この値を使用して、更新を対応する監査ログに関連付けることができます。Kelemetry は、後で監査コンシューマーからリンクできるように、オブジェクトの各 resourceVersion の差分とスナップショットを分散 KV ストアにキャッシュし、各監査ログ スパンにコントローラーによって変更されたフィールドが含まれるようにします。

resourceVersion を追跡することは、コントローラー間の 409 競合を特定するのにも役立ちます。リクエストの競合は、クライアントが resourceVersion が古すぎる UPDATE リクエストを渡し、他のリクエストが resourceVersion を変更する場合に発生します。Kelemetry は、同じ古いリソース バージョンを持つ複数の監査ログを結合して、後続の競合に関連する監査リクエストを関連するサブスパンとして表示できます。

シームレスな可用性を確保するために、コントローラーはマルチマスター選出メカニズムを使用します。これにより、コントローラーの複数のレプリカが同じクラスターを同時に監視できるようになり、コントローラーの再起動時にイベントが失われることがなくなります。

43cf545bb5e20d6e40bc5e7183fc4412.png

フロントエンド追跡コンバージョン

従来のトレースでは、スパンは常に同じプロセス (通常は同じ関数) で開始および終了します。したがって、OTLP などのトレース プロトコルは、完了後のスパンの変更をサポートしていません。残念ながら、これは Kelemetry には当てはまりません。オブジェクトは関数を実行していないため、オブジェクトのスパンを開始または停止するための専用のプロセスがありません。代わりに、Kelemetry は作成直後にオブジェクト スパンを決定し、追加データをサブスパンに書き込むため、各監査ログとイベントはオブジェクト スパンではなくサブスパン上のログになります。

ただし、監査ログの終了時刻/期間は通常ほとんど意味がないため、トレース ビューは見苦しく、スペース効率も悪くなります。

035d8207a18c39d3401e81227e35e1ee.png

ユーザー エクスペリエンスを向上させるために、Kelemetry は、Jaeger クエリ フロントエンドとストレージ バックエンドの間をインターセプトし、クエリ フロントエンドに返す前にストレージ バックエンドの結果に対してカスタム変換パイプラインを実行します。

Kelemetry は現在 4 つの変換パイプラインをサポートしています。

  • ツリー: サービス名/オペレーション名およびその他のフィールド名が簡略化された後の元のトレース ツリー

  • タイムライン: ネストされたすべての擬似スパンをトリミングし、すべてのイベント スパンをルート スパンの下に置き、監査ログを効果的に提供します。

  • トレース: 非オブジェクト スパンは、関連オブジェクトのスパン ログに平坦化されます。

dfddb67056d8a417c7e70a8042678284.png

  • グループ化: トレース パイプライン出力の上に各データ ソース (監査/イベント) の新しい疑似スパンを作成します。複数のコンポーネントがスパンを Kelemetry に送信すると、コンポーネントの所有者は自分のコンポーネントのログに注目し、他のコンポーネントのログを簡単にクロスチェックできます。

ユーザーは検索追跡時に「サービス名」を設定することで変換パイプラインを選択できます。中間ストレージ プラグインは、トレース検索結果ごとに新しい「CacheID」を生成し、それを実際の TraceID および変換パイプラインとともにキャッシュ KV に保存します。ユーザーが表示するときに、CacheID を渡します。CacheID は、仲介ストレージ プラグインによって実際の TraceID に変換され、CacheID に関連付けられた変換パイプラインが実行されます。

bd6943cdde8241d8ec13b5396044f478.png

制限時間を突破する

前述したように、一部のストレージ バックエンドで問題が発生する可能性があるため、トレースは無限に拡大することはできません。代わりに、30 分ごとに新しいトレースを開始します。これにより、12:28 に開始されるデプロイメント トレースが 12:30 に突然終了し、トレースの表示を続けるにはユーザーが 12:30 に次のトレースに手動でジャンプする必要があるため、ユーザー エクスペリエンスが混乱します。オーバーヘッド を使用すると、Kelemetry ストレージ プラグインはトレースの検索時に同じオブジェクト ラベルを持つスパンを識別し、それらを同じキャッシュ ID とユーザー指定の検索時間範囲で保存します。スパンをレンダリングするとき、関連するすべてのトラックがマージされ、同じオブジェクト ラベルを持つオブジェクト スパンが重複排除され、その子がマージされます。トラック検索の時間範囲がトラックのクリッピング範囲となり、オブジェクト グループの完全なストーリーが 1 つのトラックとして表示されます。

マルチクラスターのサポート

Kelemetry を展開して、複数のクラスターからのイベントを監視できます。ByteDance では、Kelemetry が 1 日あたり 80 億のスパン (疑似スパンを除く) を作成します (etcd の代わりにマルチラフト キャッシュ バックエンドを使用)。オブジェクトを異なるクラスタの親オブジェクトにリンクして、クラスタ間コンポーネントの追跡を可能にすることができます。

将来の機能強化

カスタム トレース ソースの使用

K8S エコシステム内のすべての観察ポイントを真に接続するには、監査とイベントだけでは十分に包括的ではありません。Kelemetry は、既存のコンポーネントからトレースを収集し、それらを Kelemetry トレース システムに統合して、システム全体の統一された特殊なビューを提供します。

バッチ分析

Kelemetry の集約トレースを使用すると、「展開のアップグレードから最初のイメージのプルまでにどのくらい時間がかかりましたか」などの質問に答えることが容易になりましたが、全体的なパフォーマンスに関する洞察を提供するためにこれらのメトリクスを大規模に集約する機能はまだ不足していました。Kelemetry のトレース出力を 30 分ごとに分析することで、一連のスパン内のパターンを特定し、それらをさまざまなシナリオに関連付けることができます。

使用例

1. replicaset controller 異常

ユーザーは、デプロイメントによって新しいポッドが作成され続けると報告しました。デプロイメント名から Kelemetry トレースをすぐに見つけて、レプリカセットとそれが作成するポッドの間の関係を分析できます。

16f519e34595a374a78f72537bdd5b07.png

追跡から、いくつかの重要なポイントがわかります。

  • SuccessfulCreateReplicaset-controllerは、Pod 作成リクエストが正常に返され、レプリカセット調整でレプリカセット コントローラーによって確認されたことを示すイベントを送信します。

  • レプリカセット ステータス更新イベントはありません。これは、レプリカセット コントローラーのポッド調整がレプリカセット ステータスの更新に失敗したか、これらのポッドが監視されなかったことを意味します。

また、いずれかの Pod のトレースを確認してください。

f2bdc9a6c1153051e6f939f2ba174d8e.png

  • Replicaset コントローラーは、ポッドの作成後、更新リクエストが失敗した場合でも、ポッドと対話することはありませんでした。

したがって、レプリカセット コントローラーのポッド キャッシュは、API サーバー上の実際のポッド ストレージと矛盾している可能性が高く、ポッド インフォーマーのパフォーマンスまたは一貫性の問題を考慮する必要があると結論付けることができます。Kelemetry を使用しない場合、この問題を特定するには、複数の apiserver インスタンスにわたる個々の Pod の監査ログを調べる必要があります。

2. 浮動minReadySeconds

ユーザーは、展開のローリング アップデートが非常に遅く、14:00 から 18:00 まで数時間かかることに気づきました。Kelemetry が使用されていない場合、kubectl を使用してオブジェクトを検索すると、minReadySeconds フィールドが 10 に設定されていることがわかり、ローリング更新時間が予想どおり長くなりません。kube-controller-manager ログには、ポッドが準備完了になるまでに 1 時間かかったことが示されています

8fd7a702d72a5d9b3ebcf3c8ac7594d0.png

kube-controller-manager ログをさらに調べると、ある時点で minReadySeconds の値が 3600 になっていることがわかります。

38b86d86b46dcca560642c250ed94de0.png

デバッグに Kelemetry を使用すると、デプロイメント名から直接トレースを見つけ、フェデレーション コンポーネントが minReadySeconds の値を増加させていることがわかります。

1f38c5e788da0a62493607295fc234b3.png

その後、デプロイメント コントローラーは値を 10 に復元します。

8857464ea4276d4fac2fa5e2bbed1b03.png

したがって、ローリング アップデート中にユーザーによって一時的に挿入された大きな minReadySeconds 値が問題の原因であると結論付けることができます。予期しない中間状態によって引き起こされる問題は、オブジェクトの差分を検査することで簡単に特定できます。

ケレメトリーを試してみる

Kelemetry は GitHub でオープンソース化されています: https://github.com/kubewharf/kelemetry

docs/QUICK_START.md クイックスタート ガイドに従って、Kelemetry がコンポーネントとどのように対話するかを試してください。クラスターをセットアップしたくない場合は、GitHub CI パイプラインから構築されたオンライン プレビューを確認してください: https://kubewharf.io /kelemetry/trace -deployment/

参加しませんか

Volcano Engine Cloud Native Team Volcano Engine Cloud Native Team は主に、ByteDance の長年にわたるクラウド ネイティブ テクノロジー スタックの経験とベスト プラクティスの蓄積と組み合わせて、パブリック クラウドでの PaaS 製品システムの構築と Volcano Engine の民営化シナリオを担当しています。企業はデジタル変革とイノベーションを加速します。製品には、コンテナ サービス、ミラー ウェアハウス、分散型クラウドネイティブ プラットフォーム、機能サービス、サービス グリッド、継続的デリバリー、監視可能なサービスなどが含まれます。

4c29c2817339b503f173bca28e404356.png

おすすめ

転載: blog.csdn.net/ByteDanceTech/article/details/131566541