3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Docker】「Grafana?なにそれおいしいの?」状態から、生成AIと作るOpenTelemetry分散トレース環境

Posted at

はじめに

「Grafana?なにそれおいしいの?」

当時の私の正直な感想は、「グラファナ……? 名前も聞いたことないけど、南国のフルーツか何か?」 というレベル。 そもそも私は「監視ツール」というもの自体に触れたことがなく、サーバーの何をどうやって見るものなのか、全く検討もつかない状態でした。

しかし、仕事で関わる可能性が高いなら、今のうちにどんなものか知っておきたい。 「ドキュメントを眺めていてもピンと来ない。実際に自分の手で監視環境を自作して、動かしながら勉強するのが一番早いのではないか?」

そう考えた私は、生成AI(Gemini) を「専属メンター」として迎え、知識ゼロの状態からローカル環境での構築実験に挑むことにしました。

本記事は、右も左も分からない未経験者が、AIと二人三脚で「Pythonアプリ → OpenTelemetry Collector → Grafana Tempo → Grafana」 という本格的な分散トレース環境を構築し、Grafanaとは何者かを理解するまでの自主学習の記録です。

AIは優秀なコードを書いてくれましたが、それでもDockerのネットワーク設定など、環境固有の問題で「動かない!」と頭を抱える場面が何度もありました。 この記事では、未経験者がどこでハマり、どうやってエラーを解消して動く状態まで持っていったのか、そのリアルな過程と解決策(コード)を共有します。

今回作るアーキテクチャ

  • App (Python/Flask): トレースデータの発生源。AIに教えてもらった「自動計装」を使用

  • OpenTelemetry Collector: データの中継・加工役

  • Grafana Tempo: トレースデータの保存バックエンド

  • Grafana: データの可視化画面

1. 設定ファイルの準備

ディレクトリを作成し、以下の3つのファイルを用意します。

1. docker-compose.yaml

各コンテナの定義です。

docker-compose.yaml
version: "3"
services:
  # 1. 可視化 (Grafana)
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - grafana-storage:/var/lib/grafana

  # 2. トレース保存 (Tempo)
  tempo:
    image: grafana/tempo:latest
    command: [ "-config.file=/etc/tempo.yaml" ]
    volumes:
      - ./tempo.yaml:/etc/tempo.yaml
    ports:
      - "3200"   # 管理用
      - "4317"   # OTLP受信 (内部通信用だが明示)

  # 3. データ中継 (OTel Collector)
  otel-collector:
    image: otel/opentelemetry-collector:latest
    command: ["--config=/etc/otel-collector-config.yaml"]
    volumes:
      - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
    ports:
      - "4317:4317" # アプリからの受信ポート
      - "4318:4318"
    depends_on:
      - tempo

volumes:
  grafana-storage:

2. tempo.yaml (Tempoの設定)

【ハマりポイント1】 デフォルト設定だと、Dockerネットワーク越しにポートがうまく開かないことがありました。0.0.0.0 を明示することで解決します。

tempo.yaml
server:
  http_listen_port: 3200

distributor:
  receivers:
    otlp:
      protocols:
        grpc:
          endpoint: "0.0.0.0:4317" # ★重要: ここで外部からの接続を許可
        http:
          endpoint: "0.0.0.0:4318"

ingester:
  trace_idle_period: 10s
  max_block_bytes: 1_000_000
  max_block_duration: 5m

compactor:
  compaction:
    compaction_window: 1h
    max_block_bytes: 100_000_000
    block_retention: 1h
    compacted_block_retention: 10m

storage:
  trace:
    backend: local
    local:
      path: /tmp/tempo/blocks
    wal:
      path: /tmp/tempo/wal

3. otel-collector-config.yaml (Collectorの設定)

【ハマりポイント2】 こちらも同様に受信側で 0.0.0.0 を指定する必要があります。また、デバッグ用に debug エクスポーターを入れておくと、データが届いているかログで確認できて便利です。

otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: "0.0.0.0:4317" # ★重要: ホスト側のアプリから受け取るため
      http:
        endpoint: "0.0.0.0:4318"

processors:
  batch:

exporters:
  otlp:
    endpoint: tempo:4317 # Docker内でのホスト名解決
    tls:
      insecure: true
  debug:
    verbosity: detailed # ログに詳細を出す

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp, debug] # Tempoへの送信とログ出力を並行

2. アプリケーションの準備(自動計装)

Pythonコードには、OpenTelemetryの記述を一切書きません。

app.py
import time
import random
from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    # ランダムな遅延を入れてグラフを見やすくする
    wait = random.uniform(0.1, 0.5)
    time.sleep(wait)
    return f"処理完了: {wait:.2f}"

if __name__ == "__main__":
    app.run(port=8081)
実行コマンド魔法の呪文 ライブラリ(opentelemetry-distro )を入れた後以下のようにラップして起動するだけでFlaskの通信が全て計測されます

Bash

opentelemetry-instrument \
    --traces_exporter otlp \
    --service_name my-flask-app \
    --exporter_otlp_endpoint http://localhost:4317 \
    --exporter_otlp_insecure true \
    python app.py

3. 起動とGrafanaの設定

Bash
docker compose up -d

Grafana (http://localhost:3000) にアクセス。

Connections -> Data sources から Tempo を追加。

URLに http://tempo:3200 を設定して Save & test。

緑色の「Data source is working」が出れば成功です!

構築中に遭遇したトラブルと解決策

今回の構築で実際にハマったポイントを共有します。

1. connection refused エラー

Collectorのログに dial tcp ... connection refused が出続けました。

原因: Tempoコンテナがデフォルト設定で起動しており、4317番ポートをリッスンしていなかった(またはローカルループバックのみだった)。

解決: tempo.yaml の grpc 設定で endpoint: "0.0.0.0:4317" を明記することで解消しました。

2. Collectorにデータが届かない

アプリを実行してもCollectorのログが反応しませんでした。

原因: Collector側の receivers 設定も 127.0.0.1 などのデフォルト値になっており、コンテナ外(ホストPC)からの通信を拒否していた。

解決: otel-collector-config.yaml の受信設定も 0.0.0.0:4317 に変更しました。

3. ポート競合 (bind: address already in use)

設定を変えて何度も docker compose up を繰り返していると、古いコンテナがゾンビのように残ってポートを占有していました。

解決: docker compose down でしっかり停止・削除してから起動し直すのが吉です。

成果:Grafanaでの可視化

Explore -> Tempo -> Search でクエリを実行すると、無事にトレース一覧が表示されました! Trace IDをクリックすると、以下のようなウォーターフォール図が表示され、処理時間が可視化できました。

image.png

まとめ

OpenTelemetryの自動計装は非常に強力で、コード変更なしに導入できるのが魅力です。 一方で、Docker環境で組む際は「コンテナ間の通信(ホスト名)」と「バインドアドレス(0.0.0.0)」の設定が一番のハードルになると感じました。

これから入門する方の参考になれば幸いです!

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?