tempo について
tempoは、OpenTelemetry向け分散トレーシングバックエンドGrafana Tempoの運用とクエリに関するスキルです。デプロイ、ストレージ、TraceQL、マルチテナンシー、トラブルシューティングを扱い、Tempoの運用チーム向けです。
主な機能
- 01Tempoのアーキテクチャとデプロイ方式の解説
- 02Helmを使ったデプロイ手順
- 03S3、GCS、Azureストレージの説明
- 04TraceQLクエリ例
- 05受信プロトコルとエンドポイントの記載
- 06マルチテナンシーと障害対応の説明
活用シーン
- 01Tempoのデプロイ方式を検討
- 02トレース用オブジェクトストレージを設定
- 03TraceQLでトレースを検索
- 04取り込み、クエリ、認可の問題を調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ julianobarbosa/ claude-code-skills --skill tempoインストール後、Claude Code で/tempoを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/configuration.mdstorage.mdtraceql.md詳細
Grafana Tempo スキル
OpenTelemetry 向けに設計された、コスト効率に優れた大規模分散トレーシングバックエンド、Grafana Tempo の包括的なガイドです。
Tempo とは?
Tempo は、次の特徴を持つ大規模分散トレーシングバックエンドです。
- トレース ID 検索モデル - すべての属性をインデックス化しないため、取り込みが高速でストレージコストを抑えられます
- OpenTelemetry ネイティブ - OTLP プロトコルを第一級でサポートします
- オブジェクトストレージを利用 - 手頃な価格の S3、GCS、Azure Blob Storage にトレースを保存します
- TraceQL クエリ言語 - PromQL と LogQL に着想を得た強力なクエリ言語です
- Apache Parquet 形式 - 従来の形式と比較して、クエリごとに読み込むデータ量を 5~10 倍削減します
- デフォルトでマルチテナント -
X-Scope-OrgIDヘッダーによるテナント分離が組み込まれています
アーキテクチャの概要
コアコンポーネント
| コンポーネント | 目的 |
|---|---|
| Distributor | トレースデータのエントリーポイントです。一貫性ハッシュリングを介して Ingester にルーティングします |
| Ingester | トレースをメモリにバッファリングし、Parquet ブロックを作成してストレージにフラッシュします |
| Query Frontend | クエリを調整し、blockID の領域をシャード化して、Querier と連携します |
| Querier | ブルームフィルターを使って、Ingester またはストレージ内のトレースを検索します |
| Compactor | ブロックを圧縮し、データの重複を排除して、保持期間を管理します |
| Metrics Generator | オプション:トレースからメトリクスを導出します |
データフロー
書き込みパス:
Applications → Collector → Distributor → Ingester → Object Storage
↓
Consistent Hash Ring
(routes by traceID)
読み取りパス:
Query Request → Query Frontend → Queriers → Ingesters (recent data)
↓ ↓
Block Sharding Object Storage (historical data)
↓ ↓
Parallel Querier Work Bloom Filters + Indexes
デプロイモード
1. モノリシックモード(-target=all)
- すべてのコンポーネントを単一プロセスで実行します
- 適している用途:ローカルテスト、小規模なデプロイ
- コンポーネント数を水平スケーリングできません
- レプリカ数を増やしてスケールします
2. スケーラブルモノリシック(-target=scalable-single-binary)
- すべてのコンポーネントを 1 つのプロセスで実行し、水平スケーリングできます
- 各インスタンスですべてのコンポーネントを実行します
- スケーリングが必要な開発環境に適しています
3. マイクロサービスモード(分散型)- 本番環境に推奨
# Using tempo-distributed Helm chart
distributor:
replicas: 3
ingester:
replicas: 3
querier:
replicas: 2
queryFrontend:
replicas: 2
compactor:
replicas: 1
Helm デプロイ
リポジトリを追加
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
分散型 Tempo をインストール
helm install tempo grafana/tempo-distributed \
--namespace monitoring \
--values values.yaml
本番環境向けの値の例
# Storage configuration
storage:
trace:
backend: azure # or s3, gcs
azure:
container_name: tempo-traces
storage_account_name: mystorageaccount
use_federated_token: true # Workload Identity
# Distributor
distributor:
replicas: 3
resources:
requests:
cpu: 500m
memory: 2Gi
limits:
memory: 4Gi
# Ingester
ingester:
replicas: 3
resources:
requests:
cpu: 1000m
memory: 2Gi
limits:
memory: 8Gi # Spikes to 8GB periodically
persistence:
enabled: true
size: 20Gi
# Querier
querier:
replicas: 2
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
memory: 4Gi
# Query Frontend
queryFrontend:
replicas: 2
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
memory: 2Gi
# Compactor
compactor:
replicas: 1
resources:
requests:
cpu: 500m
memory: 2Gi
limits:
memory: 6Gi
# Block retention
compactor:
compaction:
block_retention: 336h # 14 days
# Gateway for external access
gateway:
enabled: true
replicas: 1
# Metrics Generator (optional)
metricsGenerator:
enabled: false
ストレージの設定
Azure Blob Storage(Azure に推奨)
storage:
trace:
backend: azure
azure:
container_name: tempo-traces
storage_account_name: <storage-account-name>
# Option 1: Workload Identity (Recommended)
use_federated_token: true
# Option 2: User-Assigned Managed Identity
use_managed_identity: true
user_assigned_id: <identity-client-id>
# Option 3: Account Key (Dev only)
# storage_account_key: <account-key>
endpoint_suffix: blob.core.windows.net
hedge_requests_at: 400ms
hedge_requests_up_to: 2
AWS S3
storage:
trace:
backend: s3
s3:
bucket: my-tempo-bucket
region: us-east-1
endpoint: s3.us-east-1.amazonaws.com
# Use IAM roles or access keys
access_key: <access-key>
secret_key: <secret-key>
Google Cloud Storage
storage:
trace:
backend: gcs
gcs:
bucket_name: my-tempo-bucket
# Uses Workload Identity or service account
TraceQL クエリ言語
基本的なクエリ
# Simplest query - all spans
{ }
# Filter by service
{ resource.service.name = "frontend" }
# Filter by operation
{ span:name = "GET /api/orders" }
# Filter by status
{ span:status = error }
# Filter by duration
{ span:duration > 500ms }
# Multiple conditions
{ resource.service.name = "api" && span:status = error }
構造演算子
# Direct parent-child relationship
{ resource.service.name = "frontend" } > { resource.service.name = "api" }
# Ancestor-descendant relationship
{ span:name = "GET /api/products" } >> { span.db.system = "postgresql" }
# Sibling relationship
{ span:name = "span-a" } ~ { span:name = "span-b" }
集計関数
# Count spans
{ } | count() > 10
# Average duration
{ } | avg(span:duration) > 20ms
# Max duration
{ span:status = error } | max(span:duration)
メトリクス関数
# Rate of errors
{ span:status = error } | rate()
# Count over time
{ span:name = "GET /:endpoint" } | count_over_time()
# Percentile latency
{ span:name = "GET /:endpoint" } | quantile_over_time(span:duration, .99)
# Group by service
{ span:status = error } | rate() by(resource.service.name)
# Top 10 by error rate
{ span:status = error } | rate() by(resource.service.name) | topk(10)
トレースの構造
固有フィールド(区切り文字はコロン)
| フィールド | 説明 |
|---|---|
span:name | 操作名 |
span:duration | 経過時間(例:「10ms」、「1.5s」) |
span:status | ok、error、または unset |
span:kind | server、client、producer、consumer、internal |
trace:duration | トレース全体の時間 |
trace:rootName | ルートスパン名 |
trace:rootService | ルートスパンのサービス |
属性スコープ(区切り文字はピリオド)
| スコープ | 例 | 説明 |
|---|---|---|
span. | span.http.method | スパンレベルの属性 |
resource. | resource.service.name | リソース属性 |
event. | event.exception.message | イベント属性 |
link. | link.traceID | リンク属性 |
レシーバーのエンドポイント
| プロトコル | ポート | エンドポイント |
|---|---|---|
| OTLP gRPC | 4317 | /v1/traces |
| OTLP HTTP | 4318 | /v1/traces |
| Jaeger gRPC | 14250 | - |
| Jaeger Thrift HTTP | 14268 | /api/traces |
| Jaeger Thrift Compact | 6831 | UDP |
| Jaeger Thrift Binary | 6832 | UDP |
| Zipkin | 9411 | /api/v2/spans |
マルチテナント
# Enable multi-tenancy
multitenancy_enabled: true
# All requests must include X-Scope-OrgID header
# Example:
# curl -H "X-Scope-OrgID: tenant-1" http://tempo:3200/api/traces/<traceID>
Azure ID の設定
ワークロード ID フェデレーション(推奨)
1. AKS でワークロード ID を有効にする:
az aks update \
--name <aks-cluster> \
--resource-group <rg> \
--enable-oidc-issuer \
--enable-workload-identity
2. ユーザー割り当てマネージド ID を作成する:
az identity create \
--name tempo-identity \
--resource-group <rg>
IDENTITY_CLIENT_ID=$(az identity show --name tempo-identity --resource-group <rg> --query clientId -o tsv)
3. ストレージ権限を割り当てる:
az role assignment create \
--role "Storage Blob Data Contributor" \
--assignee-object-id <principal-id> \
--scope /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<storage>
4. フェデレーション資格情報を作成する:
az identity federated-credential create \
--name tempo-federated \
--identity-name tempo-identity \
--resource-group <rg> \
--issuer <aks-oidc-issuer-url> \
--subject system:serviceaccount:monitoring:tempo \
--audiences api://AzureADTokenExchange
5. Helm の値を設定する:
serviceAccount:
annotations:
azure.workload.identity/client-id: <IDENTITY_CLIENT_ID>
podLabels:
azure.workload.identity/use: "true"
storage:
trace:
azure:
use_federated_token: true
トラブルシューティング
よくある問題
1. コンテナーが見つからない(Azure)
az storage container create --name tempo-traces --account-name <storage>
2. 認可エラー(Azure)
# Verify RBAC assignment
az role assignment list --scope <storage-scope>
# Assign if missing
az role assignment create \
--role "Storage Blob Data Contributor" \
--assignee-object-id <principal-id> \
--scope <storage-scope>
3. Ingester のメモリ不足
ingester:
resources:
limits:
memory: 16Gi # Increase from 8Gi
4. クエリのタイムアウト
querier:
query_timeout: 5m
max_concurrent_queries: 20
診断コマンド
# Check pod status
kubectl get pods -n monitoring -l app.kubernetes.io/name=tempo
# Check distributor logs
kubectl logs -n monitoring -l app.kubernetes.io/component=distributor --tail=100
# Check ingester logs
kubectl logs -n monitoring -l app.kubernetes.io/component=ingester --tail=100
# Verify readiness
kubectl exec -it <tempo-pod> -n monitoring -- wget -qO- http://localhost:3200/ready
# Check ring status
kubectl port-forward svc/tempo-distributor 3200:3200 -n monitoring
curl http://localhost:3200/distributor/ring
API リファレンス
トレースの取得
# Get trace by ID
GET /api/traces/<traceID>
# Search traces (TraceQL)
GET /api/search?q={resource.service.name="api"}
# Search tags
GET /api/search/tags
GET /api/search/tag/<tag>/values
ヘルスチェック
GET /ready
GET /metrics
リファレンスドキュメント
トピック別の詳細な設定については、以下をご覧ください。
- ストレージの設定:オブジェクトストア、保持期間、キャッシュ
- TraceQL リファレンス:クエリ構文と例
- 設定リファレンス:設定マニフェスト全体
外部リソース
注意事項
- 保持期間はテナントごとに設定されます。グローバルの保持期間はフォールバックにすぎず、テナントの設定を誤ると、気付かないまま上書きされます。
- OTel コレクターのパイプライン末尾でのテールサンプリングでは、トレースがインフライトバッファーから解放されません。負荷が高いと、コレクターは破棄しようとしているトレースによってメモリ不足になります。
- TraceQL の
{}式はクエリ文字列ではなくフィルター式です。PromQL/LogQL とは意味が異なるため、クエリパターンをコピーして貼り付けると、気付きにくい問題が発生します。 - X-Scope-OrgID によるマルチテナント:ヘッダーが欠落している、または無効な場合は、Loki/Mimir と同様に「fake」テナントに割り当てられます。
- スパンサイズの上限(デフォルトは 1 MB):上限を超えるスパンは、属性の途中で気付かないまま切り詰められます。
discarded_spans_totalの Ingester メトリクスを確認してデバッグしてください。 - service.name と resource.service.name のどちらで検索するか:属性がスパンとリソースのどちらに設定されるかは、使用している OTel SDK によって異なります。どちらも似ていますが、インデックスの方法は異なります。
コメント
Markdown 対応