|
ByteDanceが開発したKelemetryは、Kubernetesコントロールプレーン用のトレースシステムです。複数のKubernetesコンポーネントの動作をグローバルな視点から連携させ、個々のKubernetesオブジェクトのライフサイクル全体と、異なるオブジェクト間の相互作用をトレースします。Kubernetesシステム内のイベントチェーンを可視化することで、Kubernetesシステムの監視、理解、デバッグを容易にします。 背景従来の分散トレーシングでは、「トレース」は通常、ユーザーリクエスト中の内部呼び出しに対応します。具体的には、ユーザーリクエストが到着すると、トレースはルートスパンから開始され、その後、各内部RPC呼び出しが新しい子スパンを開始します。親スパンの継続時間は通常、子スパンのスーパーセットであるため、トレースはツリーまたはフレームグラフの形式で視覚的に観察できます。階層構造はコンポーネント間の依存関係を表します。 従来のRPCシステムとは異なり、Kubernetes APIは非同期かつ宣言的です。操作を実行するために、コンポーネントはAPIサーバー上のオブジェクトの仕様(望ましい状態)を更新し、他のコンポーネントは望ましい状態を実現するために継続的に修正を試みます。例えば、レプリカセットのレプリカ数を3から5にスケールする場合、`spec.replicas`フィールドを5に更新します。rsコントローラーはこの変更を監視し、合計が5に達するまで新しいポッドオブジェクトを継続的に作成します。kubeletは、管理対象のノードがポッドを作成したことを確認すると、そのノード上にポッドの仕様に一致するコンテナを生成します。 このプロセスでは、rsコントローラーを直接呼び出すことはなく、rsコントローラーもkubeletを直接呼び出すことはありません。つまり、コンポーネント間の直接的な因果関係を観察することはできません。プロセス中に元の3つのポッドのうち1つが削除された場合、レプリカセットコントローラーは別のポッドと2つの新しいポッドを作成しますが、この作成とレプリカセットの拡張またはポッドの削除を関連付けることはできません。したがって、「トレーシング」または「スパン」の定義が曖昧なため、従来のスパンベースの分散トレーシングモデルはKubernetesではほとんど使用できません。 従来、個々のコンポーネントはそれぞれ独自の内部トレースを実装しており、通常は「調整」ごとに1つのトレースが実行されます(例:kubeletのトレースは、単一のポッド作成/更新を処理する同期操作のみを追跡します)。しかし、単一のトレースではプロセス全体を説明できず、可観測性のサイロ化につながっていました。これは、ユーザー側の多くの動作は複数の調整を観察することによってのみ理解可能だったためです。例えば、レプリカセットのスケーリングプロセスは、レプリカセットの更新またはポッド準備完了の更新を処理するレプリカセットコントローラーの複数の調整を観察することによってのみ推測可能でした。 観測可能なデータ サイロの問題に対処するために、Kelemetry は、コンポーネントに依存しない非侵入的な方法でさまざまなコンポーネントからの信号を収集して接続し、関連データをトレースの形式で表示します。 デザインオブジェクトをスパンとして使用する異なるコンポーネントからの観測可能なデータを接続するために、Kelemetryはkspanプロジェクトに着想を得た異なるアプローチを採用しています。単一の操作をルートスパンとして使用するのではなく、オブジェクト自体のスパンを作成し、そのオブジェクトで発生する各イベントを子スパンとします。さらに、オブジェクトは所有権関係によって接続されるため、子オブジェクトのスパンは親オブジェクトの子スパンとなります。これにより、オブジェクト階層とイベントのスコープを表すツリー階層と、イベントの順序を表すタイムライン(通常は因果関係と一致します)という2つの次元が得られます。 たとえば、単一のポッド デプロイメントを作成すると、監査ログとイベントのデータを使用して、デプロイメント コントローラー、rs コントローラー、および kubelet 間のやり取りを単一のトレースに表示できます。 トレースは通常、数秒しか持続しない短命なリクエストを追跡するために使用されます。そのため、トレースストレージの実装によっては、ライフサイクルが長すぎるトレースやスパンが多すぎるトレースをサポートできない場合があります。スパンが多すぎるトレースは、一部のストレージバックエンドでパフォーマンスの問題を引き起こす可能性があります。そのため、各イベントを対応する30分の期間に分割することで、各トレースの期間を30分に制限しています。例えば、12:56に発生したイベントは、12:30~13:00のオブジェクトスパンにグループ化されます。 分散キー値ストアを使用して、対応するオブジェクトによって作成されたトレース/スパン ID へのマッピング (クラスター、リソース タイプ、名前空間、名前、フィールド、30 分タイムスタンプ) を保存し、オブジェクトごとに 1 つのトレースのみが作成されるようにします。 監査ログの収集Kelemetryの主要なデータソースの一つは、APIサーバーの監査ログです。これらのログは、各コントローラー操作に関する豊富な情報を提供します。操作を開始したクライアント、関連するオブジェクト、リクエストの受信から完了までの正確な所要時間などが含まれます。Kubernetesアーキテクチャでは、各オブジェクトの変更は関連するコントローラーによる調整をトリガーし、その後、他のオブジェクトにも変更が加えられます。そのため、オブジェクトの変更に関連する監査ログを観察することで、一連のイベントにおけるコントローラー間の相互作用を理解するのに役立ちます。 Kubernetes APIサーバーの監査ログは、ログファイルとWebhookの2つの異なる方法で公開されます。一部のクラウドプロバイダーは独自の監査ログ収集方法を実装していますが、ベンダーに依存しない監査ログ収集設定方法のコミュニティにおける進展は限られています。セルフサービスクラスターの導入プロセスを簡素化するため、Kelemetryはネイティブ監査情報を受信するための監査Webhookを提供するとともに、ベンダー固有のメッセージキューから監査ログを取得するためのプラグインAPIも公開しています。 イベントコレクションKubernetesコントローラはオブジェクトを処理する際に、そのオブジェクトに関連付けられた「イベント」を発行します。これらのイベントは、ユーザーが「kubectl describe」コマンドを実行すると表示され、通常、コントローラの処理に関するよりユーザーフレンドリーな説明を提供します。例えば、スケジューラがポッドをスケジュールできない場合、詳細情報を含む「FailToSchedulePod」イベントを発行します。
イベントは「kubectl describe」コマンド用に最適化されているため、すべての生のイベントを保持するわけではなく、最後に記録されたイベントのタイムスタンプとカウントを保存します。一方、KelemetryはKubernetesのオブジェクトリスト観測APIを使用してイベントを取得し、イベントオブジェクトの最新バージョンのみを公開します。イベントの重複を避けるため、Kelemetryはいくつかのヒューリスティックを用いて、イベントをスパンとして報告すべきかどうかを「推測」します。
オブジェクトの状態を監査ログに関連付ける監査ログを分析してトラブルシューティングを行う場合、特に個々のコンポーネントのセマンティクスが不明な場合は、「誰がこのリクエストを開始したか」ではなく、「このリクエストによって何が変更されたか」が最も重要な関心事です。Kelemetryは、オブジェクトの作成、更新、削除イベントを監視し、これらのイベントを受信すると監査スパンに関連付けるコントローラーを実行します。Kubernetesオブジェクトが更新されると、その「resourceVersion」フィールドが新しい一意の値に更新されます。この値は、更新を対応する監査ログに関連付けるために使用されます。Kelemetryは、各オブジェクトの「resourceVersion」の差分とスナップショットを分散キーバリューストアにキャッシュし、後で監査コンシューマーからリンクできるようにします。これにより、各監査ログスパンにコントローラーによって変更されたフィールドが含まれるようになります。 リソースバージョンを追跡することで、コントローラー間の409競合の特定にも役立ちます。競合は、クライアントが古いリソースバージョンでUPDATEリクエストを送信し、他のリクエストがそのリソースバージョンを変更する場合に発生します。Kelemetryは、同じ古いリソースバージョンを持つ複数の監査ログを結合し、後続の競合に関連する監査リクエストを関連するサブスパンとして表示できます。 シームレスな可用性を確保するために、コントローラはマルチマスター選択メカニズムを使用して、コントローラの複数のレプリカが同じクラスターを同時に監視できるようにし、コントローラの再起動時にイベントが失われないようにします。 フロントエンドトラッキングコンバージョン従来のトレースでは、スパンは常に同じプロセス(通常は同じ関数)内で開始および終了します。そのため、OTLPなどのトレースプロトコルは、完了後のスパンの変更をサポートしていません。残念ながら、Kelemetryではこれは当てはまりません。オブジェクトは実行中の関数ではなく、スパンを開始または停止するための専用プロセスがないためです。Kelemetryはオブジェクトスパンを作成直後に決定し、その他のデータをサブスパンに書き込みます。そのため、各監査ログとイベントはオブジェクトスパン上のログではなく、サブスパンとして扱われます。 ただし、監査ログの終了時刻/期間は通常あまり重要ではないため、トレース ビューは非常に見苦しく、スペース効率も悪くなります。 ユーザー エクスペリエンスを向上させるために、Kelemetry は Jaeger クエリ フロントエンドとストレージ バックエンドの間をインターセプトし、ストレージ バックエンドの結果に対してカスタム変換パイプラインを実行してから、クエリ フロントエンドに返します。 Kelemetry は現在 4 つの変換パイプラインをサポートしています。
ユーザーは、検索をトレースする際に「サービス名」を設定することで、変換パイプラインを選択できます。中間ストレージプラグインは、トレース検索結果ごとに新しい「CacheID」を生成し、実際のTraceIDと変換パイプラインと共に、キャッシュされたキーと値のペアに保存します。ユーザーが結果を表示する際、CacheIDを渡します。中間ストレージプラグインはCacheIDを実際のTraceIDに変換し、CacheIDに関連付けられた変換パイプラインを実行します。 時間制限を破る前述のように、トラックを無制限に大きくすることはできません。一部のストレージ バックエンドで問題が発生する可能性があるためです。代わりに、30 分ごとに新しいトラックを開始します。これにより、12:28 にスクロールを開始したデプロイメント トラックが突然 12:30 に終了し、ユーザーが視聴を続けるために 12:30 に手動で次のトラックにジャンプしなければならないなど、ユーザー エクスペリエンスが混乱する可能性があります。この認知オーバーヘッドを回避するために、Kelemetry ストレージ プラグインは、トラックの検索時に同じオブジェクト ラベルを持つスパンを識別し、同じキャッシュ ID とユーザー指定の検索時間範囲とともにそれらを保存します。スパンをレンダリングするときに、関連するすべてのトラックが結合され、同じオブジェクト ラベルを持つ重複するオブジェクト スパンが削除され、その子オブジェクトが結合されます。トラックの検索時間範囲がトラックのクリッピング範囲になり、オブジェクト グループの完全なストーリーが 1 つのトラックとして表示されます。 マルチクラスタサポートKelemetryは、複数のクラスタからのイベントを監視するために導入できます。ByteDanceでは、Kelemetryは1日あたり80億のスパン(擬似スパンを除く)を作成しています(etcdではなくマルチRaftキャッシュバックエンドを使用)。オブジェクトを異なるクラスタの親オブジェクトにリンクすることで、クラスタコンポーネント間のトレースが可能になります。 将来の機能強化カスタムトレースソースを使用する監査とイベントだけでは、Kubernetesエコシステム内のすべての観測ポイントを真に網羅的に網羅することはできません。Kelemetryは既存のコンポーネントからトレースを収集し、Kelemetryトレースシステムに統合することで、システム全体を統合的に、かつプロフェッショナルに可視化します。 バッチ分析Kelemetryの集約されたトレースにより、「デプロイメントのアップグレードから最初のイメージのプルまでどれくらいの時間がかかるのか?」といった質問への回答が容易になりますが、これらのメトリクスを大規模に集約して全体的なパフォーマンスに関する洞察を提供する能力はまだ不足しています。Kelemetryのトレース出力を30分ごとに分析することで、様々な時間枠におけるパターンを特定し、それらを様々なシナリオと相関させることができます。 ユースケース1. レプリカセットコントローラの例外ユーザーから、デプロイメントが継続的に新しいポッドを作成しているという報告がありました。デプロイメント名でKelemetryトレースを簡単に見つけ、レプリカセットとそれが作成するポッドの関係を分析できます。 追跡から、いくつかの重要なポイントがわかります。
さらに、ポッドの 1 つのトレースをチェックします。
したがって、レプリカセットコントローラー内のPodキャッシュは、APIサーバー上の実際のPodストレージと不整合がある可能性が高いと結論付けられ、Pod Informerのパフォーマンスまたは整合性の問題を考慮する必要があります。Kelemetryがない場合、この問題を特定するには、複数のAPIサーバーインスタンスにまたがる個々のPodの監査ログを調べる必要があります。 2. フローティング minReadySecondsユーザーは、デプロイメントのローリングアップデートが非常に遅く、午後2時から午後6時まで数時間もかかっていることに気づきました。Kelemetryを使用せずにkubectlを使用してオブジェクトを検索したところ、minReadySecondsフィールドが10に設定されており、ローリングアップデートに予想外に長い時間がかかっていたことが分かりました。kube-controller-managerのログには、ポッドがReady状態になったのは1時間後だったことが示されていました。 kube-controller-manager ログをさらに調べたところ、ある時点で minReadySeconds の値が 3600 であったことが判明しました。 デバッグに Kelemetry を使用すると、デプロイメント名でトレースを直接検索し、フェデレーション コンポーネントによって minReadySeconds の値が増加したことを確認できます。 その後、デプロイメント コントローラーは値を 10 に復元しました。 したがって、この問題は、ローリングアップデートプロセス中にユーザーが一時的に挿入した大きなminReadySeconds値によって引き起こされたと結論付けることができます。オブジェクトの差分を調べることで、予期しない中間状態によって引き起こされた問題を容易に特定できます。 Kelemetryを試すKelemetry は GitHub でオープンソース化されています: https://github.com/kubewharf/kelemetry docs/QUICK_START.md のクイックスタート ガイドに従って、Kelemetry がコンポーネントとどのようにやり取りするかを試してみてください。クラスターをセットアップしたくない場合は、GitHub CI パイプラインから構築されたオンライン プレビューをチェックすることもできます: https://kubewharf.io/kelemetry/trace-deployment/ 参加しませんかVolcano Engineクラウドネイティブチームは、パブリッククラウドとプライベートクラウドの両方のシナリオに対応するPaaS型製品システムの構築を主に担当しています。ByteDanceの長年の経験とクラウドネイティブ技術におけるベストプラクティスを活用し、企業のデジタルトランスフォーメーションとイノベーションの加速を支援します。製品には、コンテナサービス、イメージリポジトリ、分散型クラウドネイティブプラットフォーム、ファンクションサービス、サービスメッシュ、継続的デリバリー、オブザーバビリティサービスなどがあります。 |