はじめに

前回はオブザーバビリティの概要について述べ、メトリクスとログモニタリングを設定してどのような情報が取得できるかを見てきました。

今回は、分散トレーシングについて説明し、実際にトレースデータを取得してみます。

分散トレーシングの目的

前回で「オブザーバビリティ」の特徴として「アプリケーションの動作まで踏み込んで何が起こっているのかを知る」という点を挙げました。

メトリクスやログのモニタリングも重要ですが、これらは基本的に個々のアプリケーションに閉じた事象をモニタリングしていました。しかしKubernetesを利用する典型的なシステムでは、複数のアプリケーションが通信により相互に連携して利用者にサービスを提供します。こういったシステムでは、複数のアプリケーションの組み合わせが原因で問題が発生することが往々にしてあります。

とあるアプリケーションにおいて処理が繰り返し失敗したとします。では、エラーが発生したアプリケーションを調べることで問題が修正できるでしょうか。もし失敗の原因が誤った入力が原因だったとき、失敗の原因になった入力はどのシステムから送られたものか簡単にわかるでしょうか。また、複数のアプリケーションが連携している状況で、エンドユーザからのリクエストがいくつか遅延を発生させているとき、その遅延の原因はどのアプリケーションでしょうか。応答時間の長いアプリケーションが1つ見つかったとしても、その原因はさらに別のアプリケーションからの応答が遅いことかもしれません。

このように例を挙げると、開発者の方は「それくらいのことはシステム全体の構成を把握していれば簡単なのでは」と思われるかもしれません。しかし、マイクロサービスアーキテクチャなど、分散アーキテクチャを選択するとシステムが柔軟になる一方で、アプリケーション間の連携はより複雑になる傾向があるとされます。

例としてTwittter社の事例を見てみると、2013年のブログに以下の画像が最初に挙げられています(Gory G Watchyourbackson 2013「Observability at Twitter」)。

この図ではTwitter社が運用しているアプリケーションがドーナツ状に並んでおり、円の中の曲線がそのアプリケーション間の通信を、円の外側に向かって伸びている点線のようなものが個々のアプリケーションの名前を示しています*1。アプリケーションの数とその連携の複雑さは、その全体を1人の人間が把握するには複雑すぎることがよくわかる例でしょう。

*1 この図はZipkinというTwitter社が開発した分散トレーシングシステムを使っています。今回使用しているJaegerは元々Uber社で開発されましたが、このZipkinの影響も受けているとされています。

これは少し極端な例かもしれませんが、分散アーキテクチャが成功すればするほど、アプリケーション間連携を人間が管理することが難しくなる、というのは何となく想像できるのではないでしょうか。

分散トレーシングはこういった課題に対して「システムで何が起こっているのか」を知るための1つの手段です。特に、個々のアプリケーションの詳細ではなく、1つのリクエストに注目して複数のアプリケーションがどのように連携したのかを知ることができます。

分散トレーシングの仕組み

分散トレーシングの仕組みについて簡単に説明しますが、その前にいくつか、特有の用語を紹介します。

スパン(Span)
アプリケーションの論理的な作業単位。「APIの呼び出しから応答まで」や「関数の呼び出しから終了まで」などです。スパンは作業単位の呼び出しごとに作成され、作業の開始と終了時刻などを含みます。あるスパンが別のスパンからの呼び出しで開始されたとき、呼び出された側のスパンは呼び出し元のスパンへの参照を持ち、スパンどうしの参照は有向非巡回グラフを構成します。

トレース(Trace)
一連の処理にかかわるスパン全体のあつまり。外部から直接呼び出される処理に対応するスパンを根とし、スパンをノード、呼び出し関係を辺とする有向非巡回グラフとしても表されます。

分散トレーシングはアプリケーションプロファイラに似ています。プロファイラは単一のアプリケーション内のメソッドや関数の呼び出し関係を追跡しますが、分散トレーシングではアプリケーション間の呼び出し関係を追跡します。

分散トレーシングシステムの主な構成要素は、アプリケーションに組み込まれるクライアントライブラリ、トレース情報の保管先としてのストレージ、さらに収集したトレース情報の検索や可視化を行うUIなどからなります。また、この後実際に操作するJaegerではAgentやCollectorといったこのほかに追加の構成要素もありますが、詳細は後述します。

クライアントライブラリは、そのアプリケーション内のスパン情報をストレージに送信するだけでなく、外部アプリケーションを呼び出す際はその通信プロトコルに応じた方法で呼び出し元のスパンの情報を伝え、呼び出し先ではその情報を展開して自身のスパン情報に含めてストレージに送信します。これにより、異なるアプリケーション間でスパンの呼び出し関係を引き継ぎ、分散システム全体にわたるトレース情報を構成します。

分散トレーシングシステム
Jaegerのインストール

ここからは、実際にサンプルアプリケーションのトレースを取得することで、どのような情報が得られるのかを見ていきます。今回は分散トレーシングシステムとしてJaegerを利用します。JaegerはCNCF(Cloud Native Computing Foundation)のプロジェクトとして開発されています。

まず、Jaegerを起動するために、公式サイトの手順を参考にjaeger-operatorをインストールします。

kubectl create namespace observability
kubectl create -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.27.0/deploy/crds/jaegertracing.io_jaegers_crd.yaml
kubectl create -n observability -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.27.0/deploy/service_account.yaml
kubectl create -n observability -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.27.0/deploy/role.yaml
kubectl create -n observability -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.27.0/deploy/role_binding.yaml
kubectl create -n observability -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.27.0/deploy/operator.yaml

ここで、任意のネームスペースでJaegerカスタムリソースが作成できるようにしたいので、最後に適用したマニフェストで定義されているjaeger-operatorのDeploymentリソースを修正します。jaeger-operatorコンテナのWATCH_NAMESPACE環境変数を空文字列('')に設定します。手順のように適用するマニフェストを修正してもよいですが、ここでは修正内容をファイルとして作成してkubectl patchコマンドで既にあるリソースを修正します。以

以下の内容のpatch-jaeger-operator.yamlファイルを作成します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jaeger-operator
  namespace: observability
spec:
  template:
    spec:
      containers:
      - name: jaeger-operator
        env:
        - name: WATCH_NAMESPACE
          value: ''
          valueFrom: null

以下のコマンドで今作成したファイルをパッチとして適用してネームスペースの指定を変更します。

kubectl -n observability patch deployment jaeger-operator --patch-file=patch-jaeger-operator.yaml

さらにクラスタレベルのロールも付与します。

kubectl create -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.27.0/deploy/cluster_role.yaml
kubectl create -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.27.0/deploy/cluster_role_binding.yaml

次に、Jaegerインスタンスを作成します。Jaegerは高可用性と永続ストレージを利用するためのいろいろな構成が可能ですが、今回は分散トレーシングの利用と理解を目的とするため、簡易的なall-in-oneと呼ばれる構成を利用します。この構成は、インストールが容易な反面、トレース情報がメモリに保存されるなど実用的な環境での利用を想定しない構成になっています。

Jaegerカスタムリソースのマニフェストを、以下の内容でsimplest.yamlというファイルに作成します。

apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
  name: simplest

以下のコマンドでマニフェストを適用してJaegerインスタンスを作成します。

kubectl -n default apply -f simplest.yaml

デプロイされたJaegerインスタンスに対応するPodが稼働していることを以下のコマンドで確認します。

kubectl get po -l app.kubernetes.io/instance=simplest -w

Podが稼働し始めたらUIを表示して動作を確認しましょう。以下のコマンドで作成されたServiceにport-forwardを実行します。

kubectl port-forward service/simplest-query 16686:16686

ブラウザからhttp://localhost:16686/にアクセスし、以下の画面が表示されれば正常です。

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored

ClickHouse Cloudが実現した広告運用SaaS「ATOM」のデータ基盤革新、パフォーマンスを向上しながら、運用負荷とコストを削減 11月11日 6:20 AIで開発が加速する時代、品質保証はどう変わる? Tricentisが示すAIエージェント活用の実像 11月9日 6:45 悪用までの猶予が「1分」に迫るフロンティアAI時代に開発と本番を貫く脆弱性管理が必要 10月29日 8:30 欧州CRA対応とSBOM運用。AI生成コードのOSS混入問題の対策とは ――スニペット単位で検出する「FossID」「Insignary Clarity」によるSBOM運用 9月16日 6:40 PostgreSQLからTiDBへ、稼働中SaaSで進める段階的DB移行の実践と再設計への展望 9月7日 6:30 機能安全開発におけるGoogleTestの活用を支援!「Parasoft C/C++test CT」で実現する効率化&AI連携 4月14日 6:30 【CNDW2025】Grafanaが明かす「オブザーバビリティの哲学」ー最小限の労力で実用的なインサイトを得るには 1月23日 6:30 【CNDW2025】プロダクト急増に備える基盤刷新 ーウェルスナビがECSからEKSへの移行で得た知見とは 1月15日 6:30 【CNDW2025】250環境を5人で運用、構築時間は30分に ーKINTOテクノロジーズが語るインフラ基盤組織の作り方 2025年12月18日 6:30 新たな自動化で熱視線! AIエージェントの「推論能力」を支える2つのコンポーネントとは? 2025年11月28日 6:30