「PrometheusでCPU・メモリは取れているが、特定リクエストだけ遅い原因が分からない」
そんな悩みを抱えるLinuxエンジニアは多いはずです。この記事では、OpenTelemetryとJaegerをUbuntu Serverに導入し、PythonアプリからOllamaのAPIを呼び出すリクエストをトレースとして可視化する手順を解説します。
メトリクスでは見えない「どのスパンで何ミリ秒かかったか」が追えるようになるまでを、コマンドとコードを交えて説明します。
OTel Collectorのsystemd設定から、opentelemetry-instrumentによるノーコード自動計装、JaegerのUIでスパンを読む手順まで順を追って説明します。
この記事のポイント
・opentelemetry-instrument でPythonアプリをノーコードで計装できる
・OTel CollectorはLinuxのsystemdサービスとして常駐させてトレースを受け取る
・JaegerはPodmanのall-in-oneコンテナで導入コストを最小にできる
・Prometheusのメトリクスとトレースは用途が異なり、実務では両方を使う
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜOllamaのAPIにトレースが必要なのか
Prometheusでメトリクスを取っていても、「全体のレスポンスタイムが遅い」ことは分かっても、「どのステップで時間がかかったか」は追えません。OpenTelemetryのトレースは、1リクエストの中で何が起きたかを「スパン」の単位で記録します。
典型的なケースでは、Pythonアプリ→OllamaのAPIへのHTTP接続→モデルの推論という3つの処理が直列に並びます。
遅さの原因が「アプリのコード」なのか「OllamaへのHTTP接続」なのか「モデルの推論時間」なのかは、メトリクスだけでは区別できません。
トレースを入れると、各スパンの開始・終了時刻が記録され、どこに時間がかかったかをタイムラインで確認できます。
Prometheusは「いつ遅くなったか」を教えてくれる、トレースは「なぜ遅かったか」を教えてくれる、と理解すると用途の違いが明確になります。
この記事はOllamaを構築済みの環境に追加でトレース基盤を足す構成です。
Ollamaの導入がまだであれば「Ubuntu ServerでローカルLLMを構築する方法」で先に環境を整えてください。
全体構成(Pythonアプリ → OTel Collector → Jaeger)
この記事で構築するコンポーネントは3つです。Pythonアプリ(opentelemetry-instrument でラップして実行) │ OTLPプロトコル(gRPC 4317番) ▼ OTel Collector(otelcol-contrib・systemdサービス) │ OTLPプロトコル(gRPC 14317番) ▼ Jaeger(all-in-one コンテナ・UIは16686番)
OTel CollectorはLinuxのsystemdサービスとして常駐し、受け取ったトレースをJaegerに転送します。
Jaegerはすべてのトレースを保存し、ブラウザで検索・可視化する役割を担います。
Pythonアプリが送る宛先をCollectorの1か所に固定しておくと、後からJaeger以外のバックエンドへ切り替えやすくなります。
config.yamlの `exporters` セクションを変えるだけで転送先を差し替えられるのが、Collectorを挟む主な理由です。
JaegerをPodmanでセットアップする
Jaegerはall-in-oneイメージで1コンテナにすべての機能が入っています。本番環境向けには分散構成もありますが、まず動かす用途ではall-in-oneで十分です。
#### 1. Podmanのインストールを確認する
# Podmanのバージョンを確認する $ podman --version podman version 4.9.3 # インストールされていない場合はdnfで導入する $ sudo dnf install -y podman
$ podman run -d \ --name jaeger \ -p 16686:16686 \ -p 14317:4317 \ --restart=always \ jaegertracing/all-in-one:1.57
`-p 16686:16686` はブラウザから操作するJaeger UIのポートです。
コンテナ内の4317番をホストの14317番に割り当てる理由は、ホスト側の4317番はOTel Collectorが使うためです。
#### 3. Jaeger UIの起動を確認する
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:16686 200
ブラウザで `http://サーバーのIPアドレス:16686` を開くと、Jaeger UIの画面が表示されます。
Jaegerはデフォルトではすべてのデータをメモリに保持します。
サーバーを再起動するとトレースデータが消える点は事前に把握しておいてください。
長期保存が必要な場合はElasticsearchとの連携が必要になりますが、動作確認の段階ではメモリモードで十分です。
OTel CollectorをLinuxシステムサービスとして導入する
OTel CollectorのLinux向けRPMパッケージは `otelcol-contrib` として配布されています。otelcol-contribはすべての公式プラグインを含む配布版で、Jaeger向けのエクスポーターも含まれています。
#### 1. otelcol-contribをインストールする
# GitHubのリリースページから最新のRPMをダウンロードする $ wget https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.104.0/otelcol-contrib_0.104.0_linux_amd64.rpm $ sudo rpm -ivh otelcol-contrib_0.104.0_linux_amd64.rpm $ otelcol-contrib --version otelcol-contrib version v0.104.0
受信口としてOTLP gRPCを開き、Jaegerに対してOTLPで転送する構成です。
$ sudo vi /etc/otelcol-contrib/config.yaml
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 processors: batch: timeout: 1s exporters: otlp/jaeger: endpoint: localhost:14317 tls: insecure: true service: pipelines: traces: receivers: [otlp] processors: [batch] exporters: [otlp/jaeger]
別サーバーのJaegerに転送する場合はTLSを有効にする必要があります。
#### 3. 設定ファイルを検証してサービスを起動する
# 設定ファイルの文法チェック $ otelcol-contrib validate --config /etc/otelcol-contrib/config.yaml # サービスを有効化して起動する $ sudo systemctl enable --now otelcol-contrib $ sudo systemctl status otelcol-contrib * otelcol-contrib.service - OpenTelemetry Collector Contrib Active: active (running)
起動直後にエラーが出た場合は `journalctl -u otelcol-contrib -n 30` でログを確認します。
Collectorが起動したら、4317番ポートが開いているかを確認します。
$ ss -tlnp | grep 4317 LISTEN 0 128 0.0.0.0:4317 0.0.0.0:* users:(("otelcol-contrib",pid=12345,fd=10))
PythonアプリにOpenTelemetry自動計装を設定する
OpenTelemetryには「自動計装」と「手動計装」があります。自動計装はアプリのコードを変更せずに `opentelemetry-instrument` コマンドでラップするだけでトレースが取れます。
requestsやFlask等のライブラリが入っていれば、それぞれの対応プラグインが自動でスパンを生成します。
#### 1. 計装ライブラリをインストールする
$ pip3 install opentelemetry-distro opentelemetry-exporter-otlp $ opentelemetry-bootstrap -a install
requestsが入っていれば `opentelemetry-instrumentation-requests` が追加されます。
#### 2. OllamaのAPIを呼び出すサンプルスクリプトを用意する
# ollama_client.py import requests import json def ask_ollama(prompt): url = "http://localhost:11434/api/generate" payload = { "model": "llama3.3:8b-instruct-q4_K_M", "prompt": prompt, "stream": False } res = requests.post(url, json=payload, timeout=120) data = res.json() return data.get("response", "") if __name__ == "__main__": answer = ask_ollama("Linuxのcronとsystemdタイマーの違いを1行で説明してください") print(answer)
量子化タグは `-q4_K_M` のようにサフィックス形式で書きます。
`:q4_K_M` 単体の表記は実在しないため、常にモデル名とセットで指定してください。
このスクリプト自体にOpenTelemetryのコードは一切含まれていません。
計装の設定は次のステップで `opentelemetry-instrument` を通じて外から注入します。
#### 3. opentelemetry-instrumentで計装しながら実行する
$ export OTEL_SERVICE_NAME=ollama-client $ export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 $ export OTEL_EXPORTER_OTLP_PROTOCOL=grpc $ opentelemetry-instrument python3 ollama_client.py
コードに一切手を加えずに、requestsライブラリのHTTPリクエストが自動的にトレースに記録されます。
Ollamaへのリクエスト全体のスパン時間が記録されるので、推論が遅いのかネットワークが遅いのかを区別できます。
社内ネットワークでOllamaをチームで使う構成については「社内でChatGPTが使えないときの代替手段」も参考になります。
Jaeger UIでOllamaのトレースを確認する
スクリプト実行後、ブラウザで `http://サーバーのIPアドレス:16686` を開きます。#### 1. サービスを選択してトレースを検索する 左の「Service」ドロップダウンで `ollama-client` を選択し、「Find Traces」ボタンを押します。
スクリプトを実行した時刻のトレースが一覧に表示されます。
「Service」に何も表示されない場合、Collectorへの接続や環境変数の設定を確認してください。
#### 2. スパンの内訳を確認する トレースをクリックすると、タイムラインビューが開きます。
requestsライブラリが自動生成したHTTPスパンが表示され、以下の情報が確認できます。
・HTTPメソッドとURL
・リクエスト開始からレスポンスまでの経過時間
・ステータスコード(200/500等)
典型的なケースでは `POST http://localhost:11434/api/generate` のスパンが数秒から十数秒かかります。
このスパン時間がOllamaの推論時間に相当します。
スパン時間のほとんどが推論時間であれば、アプリのコード改善ではなくモデルの選定やGPU環境の見直しが有効です。
#### 3. Min Durationで遅いリクエストだけを絞り込む Jaeger UIの検索オプションに「Min Duration」欄があります。
例えば `5s` と入力すると、5秒以上かかったトレースだけが表示されます。
特定のプロンプトや特定のモデルで遅くなるパターンを探すときに有効です。
モデルごとの推論速度のばらつきを把握したい場合は「ローカルLLMのモデルを比較する方法」の手順と組み合わせると、モデル選定の判断材料が増えます。
トレース計装でよくあるつまずきと注意点
#### Collectorにトレースが届かない まずCollectorが起動しているかを確認します。$ sudo systemctl is-active otelcol-contrib active # 4317番ポートが開いているか確認する $ ss -tlnp | grep 4317 LISTEN 0 128 0.0.0.0:4317 0.0.0.0:* users:(("otelcol-contrib",pid=12345,fd=10))
`journalctl -u otelcol-contrib -n 30` でエラーの内容を確認します。
#### Jaeger UIにトレースが表示されない CollectorからJaegerへの転送設定を確認します。
config.yamlの `endpoint: localhost:14317` が、Jaegerコンテナのホスト側OTLPポートと一致しているかを確認してください。
# JaegerコンテナのポートマッピングとステータスをPodmanで確認する $ podman ps --filter name=jaeger CONTAINER ID IMAGE STATUS PORTS abc123def456 jaegertracing/all-in-one:1.57 Up 5 hours 0.0.0.0:14317->4317/tcp, 0.0.0.0:16686->16686/tcp
コンテナが停止している場合は `podman start jaeger` で再起動します。
#### OTEL_SERVICE_NAMEを設定し忘れた 環境変数 `OTEL_SERVICE_NAME` を設定しないと、Jaeger UIのServiceドロップダウンに `unknown_service:python` と表示されます。
サービス名は実行前に必ず設定してください。
#### ファイアウォールのポート開放 別のサーバーからCollectorに送信する場合、4317番をfirewall-cmdで開放する必要があります。
$ sudo firewall-cmd --add-port=4317/tcp --permanent $ sudo firewall-cmd --reload
20年以上のサーバー運用の経験から見ると、ローカルLLM基盤にトレースを入れる価値は「再現性のないレスポンス遅延を追えるようになる」点にあります。
Prometheusのメトリクス・LokiのログとOpenTelemetryのトレースを組み合わせると、観測の三本柱が揃います。
まとめ
OllamaのAPIをOpenTelemetryで計装してJaegerでトレースを可視化する手順を解説しました。| コンポーネント | 役割 | 主なコマンド・設定 |
|---|---|---|
| Jaeger | トレースの保存・可視化 | podman run jaegertracing/all-in-one:1.57 |
| OTel Collector | トレースの受信・転送 | otelcol-contrib validate --config; systemctl enable --now otelcol-contrib |
| opentelemetry-distro | Python自動計装ライブラリ | pip3 install opentelemetry-distro opentelemetry-exporter-otlp |
| opentelemetry-bootstrap | 依存ライブラリの計装プラグイン追加 | opentelemetry-bootstrap -a install |
| opentelemetry-instrument | コード変更なしでスパンを生成 | opentelemetry-instrument python3 スクリプト名.py |
用途が異なるため、どちらかではなく両方を使う構成が実務に近い形です。
まずは自動計装でOllamaへのリクエストのスパン時間を記録し、遅延の原因を特定する習慣を作るところから始めるのが確実です。
OllamaのAPI計装からモニタリング設計まで2日間のハンズオンで体験する
OllamaへのAPI呼び出しをトレースする設定から、PrometheusやLokiと組み合わせた観測基盤の設計まで、実機GPU環境で手を動かしながら習得したい方向けに、「ローカルAIマスターセミナー」を開催しています。
少人数(最大8名)ZOOMハンズオン形式で実施しています。
・Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
・社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
・ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:OllamaのAPIをNode.jsから呼び出す方法|JavaScript・TypeScriptでローカルLLMをLinuxサーバーのWebアプリに組み込む手順
- この記事の属するカテゴリ:ローカルLLMへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます