CLOVER🍀

That was when it all began.

Grafana Tempo 2.8+MinIO+GrafanaをUbuntu Linux 24.04 LTSにインストールして、トレースデータを見てみる

これは、なにをしたくて書いたもの?

Grafanaプロジェクトの中に、分散トレーシングのバックエンドとなるGrafana Tempoという製品があります。

こちらを使って分散トレーシングを試してみたいのですが、セットアップがそれなりに大変そうなので、まずは
インストールだけをやってみます。対象はUbuntu Linux 24.04 LTSとします。

Grafana Tempo

Grafana Tempoのページはこちら。

Grafana Tempo OSS | Distributed tracing backend

ドキュメントはこちら。

Grafana Tempo | Grafana Tempo documentation

Grafana Tempoは、OSSの分散トレーシングバックエンドです。

Grafana Tempo is an open-source, easy-to-use, and high-scale distributed tracing backend.

オブジェクトストレージを要求し、Grafana、Grafana Mimir、Prometheus、Grafana Lokiとインテグレーションできます。
また、JaegerやZipkin、OpenTelemetryなどのOSSのトレーシングプロトコルと組み合わせることもできます。

Tempo is cost-efficient and only requires an object storage to operate. Tempo is deeply integrated with Grafana, Mimir, Prometheus, and Loki. You can use Tempo with open source tracing protocols, including Jaeger, Zipkin, or OpenTelemetry.

こちらのページおよびその配下には、トレースやスパンといった分散トレーシングに関する用語の説明や、トレースと
メトリクス、ログといったObservabilityに関する要素およびその関連付けに関する説明が書かれています。

Introduction | Grafana Tempo documentation

基本的な用語、概念の説明ですね。

トレースデータを収集するための構成は、こちらに書かれています。

Get started | Grafana Tempo documentation

クライアント → パイプライン(Grafana Alloy) → バックエンド(Grafana Tempo) → 可視化(Grafana)という構成ですね。
パイプラインであるGrafana Alloyはオプションのようで、クライアントから直接Grafana Tempoにトレースデータを
送信しても大丈夫そうです。

ちなみにGrafana Tempo自体の構成となると、こちらですね。

Tempo architecture | Grafana Tempo documentation

Distributor、Intester、Query Frontend、Querier、Compactor、Metrics Generatorというコンポーネントが出てくるのですが、
Grafana Mimirと似た構成ですね。

Grafana Mimir+MinIOをUbuntu Linux 24.04 LTSにインストールして、Prometheusのリモート書き込み先として使う - CLOVER🍀

ストレージに関しても似ていて、Amazon S3(および互換オブジェクトストレージ)、Azure BLOB、Google Cloud Storageを
選ぶことができます。

Hosted storage | Grafana Tempo documentation

設定ファイルについてはYAMLで記述するようで、その内容はまずはこちらを見るようなのですが…

Configure Tempo | Grafana Tempo documentation

Manifest | Grafana Tempo documentation

ソースコード見てね」だったり、「サンプルを参考にしてね」だったりとなかなかに最初のハードルが高いです。

https://github.com/grafana/tempo/tree/main/example/docker-compose

このあたりは使いながら慣れていきましょうか。

インストール方法について。Grafana Tempoは、単一のプロセスで動作しデプロイも簡単なモノリシックモード、
コンポーネントが個別のプロセスで実行されコンポーネントごとにスケールさせることもできるものの、
構成が複雑なマイクロサービスモードの2つの インストール方法があります。

Tempo can be deployed in monolithic or microservices modes.

Plan your Tempo deployment | Grafana Tempo documentation

今回はLinux向けのインストール方法で、モノリシックモードとしてインストールすることにします。

Deploy on Linux | Grafana Tempo documentation

お題

今回のお題は、以下とします。

flowchart LR
    A["アプリケーション"] -- テレメトリーデータ --> B["Grafana Tempo"]
    B -- データソース --> C["Grafana"]
    B -- テレメトリーデータ --> D["MinIO"]

簡単なアプリケーションからテレメトリーデータ(トレースシグナル)をGrafana Tempoに送信して、Grafanaで見てみます。
Grafana Tempoのデータの保存先はMinIOとします。

環境

今回の環境はこちら。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 24.04.3 LTS
Release:        24.04
Codename:       noble


$ uname -srvmpio
Linux 6.8.0-71-generic #71-Ubuntu SMP PREEMPT_DYNAMIC Tue Jul 22 16:52:38 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

またGrafana Tempoが動作するサーバーのIPアドレスは、192.168.33.11とします。

アプリケーションはPythonで作成します。

$ python3 --version
Python 3.12.3


$ uv --version
uv 0.8.8

準備

Grafana Tempoを除く、各構成要素をインストールします。

Grafana。

$ sudo apt install apt-transport-https software-properties-common wget
$ sudo mkdir -p /etc/apt/keyrings/
$ wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
$ echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
$ sudo apt update
$ sudo apt install grafana
$ sudo systemctl enable grafana-server
$ sudo systemctl start grafana-server
$ grafana-server --version
Version 12.1.0 (commit: ccd7b6ce7ea6184b8c7eb1de044174147dd9a648, branch: HEAD)

MinIO。

$ curl -LO https://dl.min.io/server/minio/release/linux-amd64/minio_20250723155402.0.0_amd64.deb
$ sudo dpkg -i minio_20250723155402.0.0_amd64.deb
$ sudo systemctl enable minio

$ sudo useradd -s /bin/false minio-user
$ sudo mkdir -p /var/lib/minio
$ sudo chown minio-user:minio-user /var/lib/minio

/etc/default/minio

MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin

MINIO_VOLUMES=/var/lib/minio

MINIO_OPTS='--console-address :9001'

起動。

$ sudo systemctl start minio

MinIOクライアント。

$ curl -LO https://dl.min.io/client/mc/release/linux-amd64/mcli_20250721052808.0.0_amd64.deb
$ sudo dpkg -i mcli_20250721052808.0.0_amd64.deb
$ mcli --version
mcli version RELEASE.2025-07-21T05-28-08Z (commit-id=ee72571936f15b0e65dc8b4a231a4dd445e5ccb6)
Runtime: go1.24.5 linux/amd64
Copyright (c) 2015-2025 MinIO, Inc.
License GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>

ひとまず、Grafana Tempo以外のミドルウェアはインストールできました。

Grafana Tempoをインストールする

では、こちらに沿ってGrafana Tempoをインストールしていきます。

Deploy on Linux | Grafana Tempo documentation

Grafana TempoのインストーラGitHub Releasesから取得するようです。

Releases · grafana/tempo · GitHub

今回はdebパッケージを選択します。

$ curl -LO https://github.com/grafana/tempo/releases/download/v2.8.2/tempo_2.8.2_linux_amd64.deb

インストール。

$ sudo dpkg -i tempo_2.8.2_linux_amd64.deb

この時点でsystemdのユニットとして登録され、起動しているようです。

$ sudo systemctl status tempo
● tempo.service - Tempo service
     Loaded: loaded (/etc/systemd/system/tempo.service; enabled; preset: enabled)
     Active: active (running) since Sun 2025-08-10 16:11:48 JST; 15s ago
   Main PID: 2445 (tempo)
      Tasks: 6 (limit: 9487)
     Memory: 19.5M (peak: 19.7M)
        CPU: 107ms
     CGroup: /system.slice/tempo.service
             └─2445 /usr/bin/tempo -config.file /etc/tempo/config.yml

パッケージに含まれているファイルを確認。

/etc
/etc/systemd
/etc/systemd/system
/etc/systemd/system/tempo.service
/etc/tempo
/etc/tempo/config.yml
/usr
/usr/bin
/usr/bin/tempo
/usr/bin/tempo-cli
/usr/bin/tempo-query

systemdのユニット定義ファイル。

/etc/systemd/system/tempo.service

[Unit]
Description=Tempo service
After=network.target

[Service]
Type=simple
User=tempo
ExecStart=/usr/bin/tempo -config.file /etc/tempo/config.yml
# Give a reasonable amount of time for the server to start up/shut down
TimeoutSec = 120
Restart = on-failure
RestartSec = 2

[Install]
WantedBy=multi-user.target

デフォルトの設定ファイル。

/etc/tempo/config.yml

stream_over_http_enabled: true
server:
  http_listen_port: 3200
  log_level: info

query_frontend:
  search:
    duration_slo: 5s
    throughput_bytes_slo: 1.073741824e+09
    metadata_slo:
        duration_slo: 5s
        throughput_bytes_slo: 1.073741824e+09
  trace_by_id:
    duration_slo: 5s

distributor:
  receivers:
    otlp:
      protocols:
        grpc:
          endpoint: "0.0.0.0:4317"

metrics_generator:
  registry:
    external_labels:
      source: tempo
      cluster: docker-compose
  storage:
    path: /var/tempo/generator/wal
    remote_write:
      - url: http://prometheus:9090/api/v1/write
        send_exemplars: true
  traces_storage:
    path: /var/tempo/generator/traces

storage:
  trace:
    backend: local                     # backend configuration to use
    wal:
      path: /var/tempo/wal             # where to store the wal locally
    local:
      path: /var/tempo/blocks

overrides:
  defaults:
    metrics_generator:
      processors: [service-graphs, span-metrics, local-blocks] # enables metrics generator
      generate_native_histograms: both

Grafana Tempoは4317ポートを使うみたいですね。

distributor:
  receivers:
    otlp:
      protocols:
        grpc:
          endpoint: "0.0.0.0:4317"

またストレージはローカルファイルシステムを使うようです。

storage:
  trace:
    backend: local                     # backend configuration to use
    wal:
      path: /var/tempo/wal             # where to store the wal locally
    local:
      path: /var/tempo/blocks

こちらを見るとローカルファイルシステムの記述はないのですが

Hosted storage | Grafana Tempo documentation

こちらを見ると使えそうではあります。

Configure Tempo / Storage / Local storage recommendations

オブジェクトストレージとの併用は不可だそうです。

Grafana TempoでMinIOを使うように設定する

Amazon S3などで利用する場合の設定例はこちら。

Configure Tempo / Storage / Storage block configuration example

内容がGrafana Mimirそっくりです。

MinIOのバケットを作成しましょう。

$ mcli alias set myminio http://localhost:9000 minioadmin minioadmin
$ mcli mb myminio/tempo-blocks

Grafana Tempoの設定は以下のように変更。

/etc/tempo/config.yml

stream_over_http_enabled: true
server:
  http_listen_port: 3200
  log_level: info

query_frontend:
  search:
    duration_slo: 5s
    throughput_bytes_slo: 1.073741824e+09
    metadata_slo:
        duration_slo: 5s
        throughput_bytes_slo: 1.073741824e+09
  trace_by_id:
    duration_slo: 5s

distributor:
  receivers:
    otlp:
      protocols:
        grpc:
          endpoint: "0.0.0.0:4317"
        http:
          endpoint: "0.0.0.0:4318"

metrics_generator:
  registry:
    external_labels:
      source: tempo
      cluster: docker-compose
  storage:
    path: /var/tempo/generator/wal
    remote_write:
      - url: http://prometheus:9090/api/v1/write
        send_exemplars: true
  traces_storage:
    path: /var/tempo/generator/traces

storage:
  trace:
    backend: s3
    s3:
      bucket: "tempo-blocks"
      endpoint: "localhost:9000"
      insecure: true
      forcepathstyle: true
      access_key: "minioadmin"
      secret_key: "minioadmin"
    wal:
      path: /var/tempo/wal             # where to store the wal locally

overrides:
  defaults:
    metrics_generator:
      processors: [service-graphs, span-metrics, local-blocks] # enables metrics generator
      generate_native_histograms: both

変更箇所は、まずはストレージの部分から。

storage:
  trace:
    backend: s3
    s3:
      bucket: "tempo-blocks"
      endpoint: "localhost:9000"
      insecure: true
      forcepathstyle: true
      access_key: "minioadmin"
      secret_key: "minioadmin"
    wal:
      path: /var/tempo/wal             # where to store the wal locally

ストレージのバックエンドをAmazon S3にしていますが、実体はMinIOです。forcepathstyleは設定しなくても大丈夫そうでした。
WALはローカルファイルシステムのままにしています。

あとは、トレースデータを受信するプロトコルhttp/protobufも扱えるようにしました。

distributor:
  receivers:
    otlp:
      protocols:
        grpc:
          endpoint: "0.0.0.0:4317"
        http:
          endpoint: "0.0.0.0:4318"

Grafana Tempoを再起動。

$ sudo systemctl restart tempo

これで準備は完了です。

アプリケーションからテレメトリーデータ(トレースシグナル)を送信して確認してみる

設定が終わったので、今度は確認です。

テレメトリーデータを送信しないとどうにもならないので、PythonとFastAPIで簡単なアプリケーションを作成します。

$ uv init --vcs none tempo-test
$ uv add fastapi[standard]
$ uv pip install opentelemetry-distro opentelemetry-exporter-otlp
$ uv run opentelemetry-bootstrap -a requirements | uv pip install --requirement -

pyproject.toml

[project]
name = "tempo-test"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "fastapi[standard]>=0.116.1",
]

依存関係の一覧はこちら。

$ uv pip list
Package                                   Version
----------------------------------------- --------
annotated-types                           0.7.0
anyio                                     4.10.0
asgiref                                   3.9.1
certifi                                   2025.8.3
charset-normalizer                        3.4.3
click                                     8.2.1
dnspython                                 2.7.0
email-validator                           2.2.0
fastapi                                   0.116.1
fastapi-cli                               0.0.8
fastapi-cloud-cli                         0.1.5
googleapis-common-protos                  1.70.0
grpcio                                    1.74.0
h11                                       0.16.0
httpcore                                  1.0.9
httptools                                 0.6.4
httpx                                     0.28.1
idna                                      3.10
importlib-metadata                        8.7.0
jinja2                                    3.1.6
markdown-it-py                            3.0.0
markupsafe                                3.0.2
mdurl                                     0.1.2
opentelemetry-api                         1.36.0
opentelemetry-distro                      0.57b0
opentelemetry-exporter-otlp               1.36.0
opentelemetry-exporter-otlp-proto-common  1.36.0
opentelemetry-exporter-otlp-proto-grpc    1.36.0
opentelemetry-exporter-otlp-proto-http    1.36.0
opentelemetry-instrumentation             0.57b0
opentelemetry-instrumentation-asgi        0.57b0
opentelemetry-instrumentation-asyncio     0.57b0
opentelemetry-instrumentation-click       0.57b0
opentelemetry-instrumentation-dbapi       0.57b0
opentelemetry-instrumentation-fastapi     0.57b0
opentelemetry-instrumentation-grpc        0.57b0
opentelemetry-instrumentation-httpx       0.57b0
opentelemetry-instrumentation-jinja2      0.57b0
opentelemetry-instrumentation-logging     0.57b0
opentelemetry-instrumentation-requests    0.57b0
opentelemetry-instrumentation-sqlite3     0.57b0
opentelemetry-instrumentation-starlette   0.57b0
opentelemetry-instrumentation-threading   0.57b0
opentelemetry-instrumentation-tortoiseorm 0.57b0
opentelemetry-instrumentation-urllib      0.57b0
opentelemetry-instrumentation-urllib3     0.57b0
opentelemetry-instrumentation-wsgi        0.57b0
opentelemetry-proto                       1.36.0
opentelemetry-sdk                         1.36.0
opentelemetry-semantic-conventions        0.57b0
opentelemetry-util-http                   0.57b0
packaging                                 25.0
protobuf                                  6.31.1
pydantic                                  2.11.7
pydantic-core                             2.33.2
pygments                                  2.19.2
python-dotenv                             1.1.1
python-multipart                          0.0.20
pyyaml                                    6.0.2
requests                                  2.32.4
rich                                      14.1.0
rich-toolkit                              0.14.9
rignore                                   0.6.4
sentry-sdk                                2.34.1
shellingham                               1.5.4
sniffio                                   1.3.1
starlette                                 0.47.2
typer                                     0.16.0
typing-extensions                         4.14.1
typing-inspection                         0.4.1
urllib3                                   2.5.0
uvicorn                                   0.35.0
uvloop                                    0.21.0
watchfiles                                1.1.0
websockets                                15.0.1
wrapt                                     1.17.2
zipp                                      3.23.0

作成したソースコードはこちら。

main.py

import fastapi
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor

app = fastapi.FastAPI()

@app.get("/foobar")
async def foobar():
    return {"message": "hello world"}

FastAPIInstrumentor.instrument_app(app)

ソースコードはこちらをそのまま使いました。

OpenTelemetry FastAPI Instrumentation — OpenTelemetry Python Contrib documentation

uvとOpenTelemetryのゼロ計装は相性が悪いようで、こちらに沿って設定。

Troubleshooting Python automatic instrumentation issues | OpenTelemetry

このあたりのことですね。ここは主題ではないので、またおいおい見ていきます。

$ uv pip install opentelemetry-distro opentelemetry-exporter-otlp
$ uv run opentelemetry-bootstrap -a requirements | uv pip install --requirement -

OpenTelemetry SDK環境変数の設定。

$ export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
$ export OTEL_TRACES_EXPORTER=otlp
$ export OTEL_METRICS_EXPORTER=none
$ export OTEL_LOGS_EXPORTER=none
$ export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://192.168.33.11:4318/v1/traces
$ export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf
$ export OTEL_SERVICE_NAME=app

エンドポイントのパスはこちらから確認しました。

Tempo HTTP API | Grafana Tempo documentation

Push spans with HTTP | Grafana Tempo documentation

アプリケーションを実行。

$ uv run opentelemetry-instrument fastapi run main.py

あとはアプリケーションにリクエストを何回か投げてみます。

$ curl localhost:8000/foobar
{"message":"hello world"}

送信したテレメトリーデータをGrafanaから見てみましょう。

データソースにGrafana Tempoを選択。

接続先だけ設定してデータソースを追加。ポートは3200のようです。

結果は、Drilldownから確認。

Exploreからトレースを選ぶと

スパンツリーを見れます。

ひとまず、このくらいでしょうか…。

なお、MinIOはこのようになっていました。

$ mcli ls myminio/tempo-blocks
[2025-08-10 16:40:30 JST]   219B STANDARD tempo_cluster_seed.json
[2025-08-10 18:04:52 JST]     0B single-tenant/


$ mcli ls myminio/tempo-blocks/single-tenant/
[2025-08-10 18:02:09 JST]   302B STANDARD index.json.gz
[2025-08-10 18:02:09 JST]   110B STANDARD index.pb.zst
[2025-08-10 18:04:58 JST]     0B fa58253f-d6d2-4d05-a691-d163325b01b1/


$ mcli ls myminio/tempo-blocks/single-tenant/fa58253f-d6d2-4d05-a691-d163325b01b1/
[2025-08-10 17:52:18 JST] 100KiB STANDARD bloom-0
[2025-08-10 17:52:18 JST]  34KiB STANDARD data.parquet
[2025-08-10 17:52:18 JST]    42B STANDARD index
[2025-08-10 17:52:18 JST]   333B STANDARD meta.json

おわりに

Grafana Tempo 2.8+MinIO+GrafanaをUbuntu Linux 24.04 LTSにインストールして、トレースデータを見るところまで
やってみました。

1番苦労したのは、PythonアプリケーションにOpenTelemetry SDKのゼロ計装を適用するところだったりするので、
ここはまた後で見ておこうと思います…。

それから、Grafana上でどう見たらいいのかもだいぶ迷いました。

これからGrafanaで見ていくことになるので、慣れていかないとですね。