OTel デモを壊しました

長い間デモを運用してきた方は、最近いくつかの構造的な変更に気づいたかもしれませんし、期待どおりに動作しなくなったことに怒りを覚えたかもしれません。 その気持ちはよくわかりますし、十分に理解しています。 残念ながら、既存のフローを壊さずに変更を行う方法はありませんでした。

以前のものは一部なくなりました。 新しいサービスが追加されました。 属性名が変更されました。 カスタムメトリクスのダッシュボードを持っていた方は、すべてが壊れているはずです。

これは偶然ではありません。

OTel デモは常にリビングリファレンス実装であり、コミュニティが OTel で何ができるかを示す場所でした。 しばらくすると、私たちが目指す方向の妨げになるものが蓄積されていきました。 3.0 は、それを一掃する取り組みです。 意図的に、短期的な痛みを伴うことを承知の上で、明確な目的を持って行いました。

以下が主な変更点です。

何を壊したか(そしてなぜ)

アップグレードするとすぐに影響を受ける変更が2つあります。 1つはダッシュボードを壊し、もう1つはローカルやフォークでのデモの実行方法を壊します。

誰も望まなかったが全員が必要としていたリネーム

この変更はすべてのサービスに影響し、既存のダッシュボードやクエリを壊すため、独立したセクションにする価値があります。 すべてのカスタムテレメトリー属性が app.* から demo.* にリネームされました。

すべてです。 app.product.id は demo.product.id になりました。 app.order.id は demo.order.id に。 app.payment.amount は demo.payment.amount に。 すべてのサービスにわたって同様です。 しかし、なぜでしょうか。

2022年に OTel デモを始めた頃、app.* は予約済みの属性ではなく、その名前空間ですべてのカスタム属性とメトリクスを構築していました。 時が経ち、2023年に app.* がクライアントサイドアプリケーション(ウェブアプリやモバイルアプリなど)に関連する属性を表すためにプロジェクトに追加されました。

しかし、それが2023年に導入されたのに、なぜデモはまだ使い続けていたのでしょうか。

主な理由は2つあると考えられます。

  • それを支援するツールが必要でした。
  • タスクを手伝ってくれるコントリビューターがもっと必要でした。

1つ目は、Martin Thwaites が OpenTelemetry Weaver をデモに導入したことで解決されました。 2つ目は、Bloomberg メンターシップを通じてデモのコントリビューターになった Florian Bourgey の協力で解決されました。 これは、OTel デモが OTel エコシステム全体とどれほど密接に結びついているかを示しています。

docker-compose.yaml から compose.yaml へ、そしてユースケースごとのモード

もう1つの破壊的変更として、docker-compose.yaml はなくなりました。 compose.yaml に変わり、複数のファイルに分割され、フルのデフォルトスタックから Kafka やオブザーバビリティスタック、またはその両方を省いた軽量な構成まで、デモの実行方法を複数サポートするようになりました。

なぜそこまでする必要があったのでしょうか。 理由は2つ、メンテナビリティとフォーク所有者の負担軽減です。 OTel デモは OTel org の中で最もフォークされたプロジェクトで、6,859のフォークがあります。 この設定変更可能な仕組みにより、フォークのメンテナーは compose ファイルと Collector 設定の完全なコピーを持ち続ける必要がなくなり、変更を上から重ねるだけで済むようになります。 また、独自のバックエンドをデプロイするベンダーは、私たちのオブザーバビリティスタックを手作業で取り除くかわりに、それなしでデモを実行できるようになります。

何を追加したか

破壊的変更が片付いたところで、3.0 で本当に新しくなったものを紹介します。

目玉の新機能:エージェンティックデモ

エージェンティック AI システムをトレースしようとして、そもそもどのような姿になるべきなのか疑問に思ったことはありませんか。 「エージェントがどのツールを使うか決定した」を表すスパンは何でしょうか。 キャッシュが絡む場合、LLM のレイテンシーをどう測定するのでしょうか。 エンドツーエンドの完全なトレースはどのように見えるのでしょうか。 エージェントがツールを呼び出すために使った引数は何だったのでしょうか。 ワークフロー全体の合計トークン使用量はどれくらいだったのでしょうか。

3.0 は、ついにこれらの疑問に対する真の答えを提供します。

この機能をマージするまでにはかなりの時間がかかりました。

完全で観測可能な AI スタックを構成する3つのまったく新しいサービスを追加しました。

  • ユーザーリクエストを受け取り、それについて推論し、呼び出すべき適切なツールを選んでユーザーにレスポンスを返す LangGraph ReAct エージェント。 生成されたレスポンスに対してフォローアップの質問ができるマルチターンリクエストもサポートしています。
  • デモの機能をエージェントが検出・呼び出しできるツールとして公開する Model Context Protocol(MCP)サーバー。
  • 実際のユーザーがエージェントとリアルタイムでやり取りできるチャットボット UI。

エージェントはネイティブの LangGraph ツールと MCP ツールの両方をサポートし、LLM レスポンスキャッシュを含み、(私たちにとって最も重要な点として)OpenTelemetry で完全に計装されています。 すべてのツール呼び出し、すべての LLM インタラクション、すべての推論ステップが、チャットボットからエージェント、エージェントから MCP、MCP から他のマイクロサービスへフロントエンド経由で、そしてユーザーに戻るまでの分散トレーシング機能を提供します。 生成されるすべてのテレメトリーデータは OTel Collector パイプラインを通じて流れます。

OTel パイプラインといえば、私たちは OpenTelemetry デモとして OTel セマンティック規約に従っているため、Traceloop/OpenLLMetry のテレメトリーを公式の gen_ai.* semconv に変換する gen-ai normalizer processor も Collector に追加しました。

AI システムを構築していて、OpenTelemetry でどのように適切に観測するか考えているなら、デモを実行してまさにその姿を確認できます。

継続的プロファイリング

継続的プロファイリングは、長い間デモに取り入れたいと思っていたものです。 2024年にそのディスカッションを始めました。 3.0 でついに搭載されます。 バックエンドとして firepit を使用し、プロファイルを閲覧するための Web UI を備えた継続的プロファイリングサポートを追加しました。 デモはこれで完全な全体像をカバーします。 トレース、メトリクス、ログ、プロファイルのすべてが同じパイプラインを通じて流れます。

OpAMP サーバー

デモではすべてのシグナルが1つの Collector インスタンスに送信されますが、実際のデプロイメントでは Collector を1つだけ動かすことはありません。 数十台、場合によっては数千台が、サービス、リージョン、チームにまたがって分散しています。 そのスケールになると、新たな疑問が浮かびます。 各 Collector がどの設定で動作しているかをどうやって把握し、すべてのマシンに SSH でログインせずにどうやって変更するのでしょうか。

これが Open Agent Management Protocol(OpAMP)が解決するために存在する問題であり、3.0 ではエンドツーエンドで動作する様子を確認できるよう、OpAMP サーバーをデモに追加しました。

仕組みとしては、Collector には OpAMP エクステンションが組み込まれています。 それが設定されると、エクステンションは OpAMP サーバーへの WebSocket 接続を開き、Collector の状態(バージョン、OS、現在の設定、ヘルスステータス)を継続的に報告し始めます。

デモでは、http://localhost:8080/opamp/ でこの様子を確認できます。 UI では Collector がレポートしているのが表示され、Collector のすべての詳細と完全なアクティブ設定を確認できます。

これは、リモート設定変更が可能になる将来のアップデートの基盤です。

何を改善したか

3.0 は新しいものと壊れたものだけではありません。 デモの既存の部分もより良くしました。

本番環境の再現

実際の本番システムでは、複数の計装標準が共存しています。 まっさらな状態から始められるわけではありません。 その現実を反映するため、Ad サービスがカスタムの demo_ad_served_total{category} カウンターを持つ Prometheus /metrics エンドポイントを公開し、OTel Collector が prometheus/ad レシーバーを通じてスクレイプするようになりました。 これにより、デモは本番環境で実際に遭遇するものに近づきます。 すべてのサービスが同じ計装言語を話すわけではなく、OTel Collector がそれらを統合する役割を果たすシステムです。

また、Product Catalog サービスに SQLCommenter サポートを追加しました。 データベースクエリが SQL コメントに埋め込まれた OpenTelemetry トレースコンテキストを伝搬するようになり、分散トレースと PostgreSQL クエリログの紐付けが可能になりました。 これは実際のオブザーバビリティ業務から直接取り入れたパターンです。

新しい負荷生成ツール

Locust は最初のリリースから使われていましたが、大きな Python 依存ツリー(1000行超のピン留めされた requirements)を伴っていました。 3.0 では k6 に置き換えました。 k6 は単一の Go バイナリとして提供される負荷テストツールで、負荷テストスクリプトもゼロから再構築しました。

中心となるのは新しいカスタムエクステンション xk6-otel で、OpenTelemetry Go SDK を k6 の JavaScript ランタイムに直接ブリッジします。 すべてのシナリオがタスクごとに実際の OTel スパンを開き、すべてのリクエストに W3C traceparent を注入し、旧 Locust のフックが行っていたのと同じバゲージを伝搬するため、負荷生成ツールのトラフィックは以前のものと同じように見えます。

ただし、主な利点が2つあります。 k6 自体の組み込みテストメトリクス(仮想ユーザー(VU)、リクエスト時間など)が OTLP 経由で出力されるため、「テストのパフォーマンス」と「テストが生成したもの」の両方が同じパイプラインに集約されます。 そして最も印象的なのはメモリ消費量です。 新しい負荷生成ツールは 512 MiB のメモリ制限で動作しますが、Locust は 1,500 MiB を使用していました。

新しいテストスイート

エンドツーエンドのオブザーバビリティパイプラインを実際に検証するテレメトリーサニティテストフレームワークを構築しました。 このフレームワークは Jaeger のトレースを走査してサービス間のエッジを検証し(すべてのスパンがシステムを正しく流れていることを確認)、Prometheus のメトリクス、OpenSearch のログも検証します。

リリースノートとしては派手な仕事ではありませんが、これが存在するようになってから、より自信を持って PR をマージできるようになったと確実に言えます。

地味だが重要な仕事:62件の脆弱性バックログの解消

このリリースのすべてが新しいサービスや機能というわけではありません。 静かに積み上がっていた負債の一部であり、このサイクルでその大部分を返済しました。

今年の初め、Piotr Kiełkowicz がデモの OpenSSF Scorecard の結果を確認した後に連絡をくれました。 62件の脆弱性がフラグされており、その大半は増え続ける未マージの Dependabot PR に起因するものでした。 このバックログが存在していたのは、ありふれた、しかしよくある理由からです。 メンテナーの帯域幅です。 承認者の数が限られる中、依存関係の更新がレビューされ確信を持ってマージされるよりも速くキューに溜まっていきました。 そしてこの確信こそが真のボトルネックでした。 このサイズのプロジェクトに対して、何かが静かに壊れていないか確認する手段なしに、依存関係の一斉更新をマージしたい人はいません。

Piotr がバックログを少しずつ解消し始め、それがこのリリースのもう1つの要素とうまくタイミングが合いました。 すでに述べたテレメトリーサニティテストフレームワークです。 トレース、メトリクス、ログをエンドツーエンドで自動チェックできるようになったことで、依存関係の更新のマージが一か八かの賭けではなくなりました。 この確信があったからこそ、バックログは増え続けるのではなく実際に解消に向かいました。

結果として、フラグされた62件が一桁にまで減り、その過程で依存関係グラフ全体のクリーンアップに勢いがつき、合計300超の CVE が解決されました。 このおかげでプロジェクトは目に見えて健全になりました。

3.0 が示す方向性

一歩引いてこのリリースの全体像を見ると、OpenTelemetry デモはもはや単なる「ショッピングカートをトレースする」リファレンスアプリではありません。 以下をカバーする包括的なマルチシグナルリファレンスとなりました。

  • エージェンティック AI システムとその計装方法
  • トレース、メトリクス、ログと並ぶ継続的プロファイリング
  • ゼロコード計装と手動計装の両方を示す混合計装セットアップ
  • テレメトリーを伴う OpenFeature フラグ評価
  • SQLCommenter によるデータベースクエリの紐付け
  • 実際の本番シナリオを再現するための異なる標準

そして、1つのブログ記事には収まりきらない多くの改善もあります。

行動の呼びかけ

属性のリネームと compose.yaml への移行により、あなたのフォークやベンダー手順はどこかが壊れています。 まとめとして、OTel デモを自社のバックエンドにデータを送信するよう設定する手順を持つすべてのベンダーへ行動を呼びかけます(はい、メインの README にリストされている45社すべてです)。 現在の手順を確認して更新してください。 もう動作しません。 すべての更新を追跡するイシューを作成しており、3.0 リリースから60日後にメイン README からチェックされていないエントリを削除する予定です。

ありがとうございます

これはすべて、貢献してくれた人々なしでは実現しませんでした。 PR を作成した方、レビューした方、イシューを報告した方、このサイクル中に Special Interest Group(SIG)のコールに参加した方全員に、大きな感謝を送ります。 クリーンアップの PR、テレメトリーのリネーム、新しいサービス、すべてがコミュニティの仕事であり、それがよく表れています。

特に感謝を伝えたい方々:

  • Felix George、エージェンティックサービスのマージを忍耐と献身で実現してくれたこと。
  • Dónal O’Sullivan と Florian Lehner、継続的プロファイリングと firepit の実装。
  • Martin Thwaites、OpenTelemetry Weaver をデモに導入してくれたこと。
  • Florian Bourgey、属性リネーム作業を推進してくれたこと。
  • Shenoy Pratik、テレメトリーサニティテストスイートを構築してくれたこと。
  • Cijo Thomas、OpAMP サーバーを実現してくれたこと。
  • Matthew Wimpelberg、k6 負荷生成ツールへの移行を推進してくれたこと。
  • Piotr Kiełkowicz、脆弱性バックログがなくなるまで粘り強く解消してくれたこと。

私たちはより良いものを作るためにデモを壊しました。 3.0 がアップグレードに値するものであることを願っています。

ぜひ試してみて、感想を聞かせてください。 イシューを作成するか、SIG のコールに参加するか、CNCF Slack で見つけてください。 このプロジェクトはそうやって進んでいきます。