- はじめに
- OpenTelemetry のアーキテクチャと Collector の役割
- 分散トレーシングツールの比較: OpenTelemetry / Jaeger / Zipkin
- Receiver-Processor-Exporter パイプラインの構成
- Receiver の詳細設定
- Processor の詳細設定
- さまざまなバックエンドとの連携
- Kubernetes 環境でのデプロイ戦略
- サンプリング戦略
- パフォーマンスチューニングと高可用性の構成
- トラブルシューティングガイド
- 障害事例と復旧手順
- 運用チェックリスト
- おわりに
- 参考資料

はじめに
マイクロサービスアーキテクチャが一般化するにつれ、可観測性 (Observability) は選択肢ではなく必須になった。数十から数百のサービスが相互に通信する分散環境で、Traces、Metrics、Logs という三つのテレメトリシグナルを効率よく収集し処理することは、安定したサービス運用の基本的な前提条件である。
OpenTelemetry Collector は CNCF (Cloud Native Computing Foundation) の Graduated プロジェクトである OpenTelemetry の中核コンポーネントで、ベンダーに依存しないテレメトリパイプラインを提供する。アプリケーションが生成したテレメトリデータを受信 (Receiver) し、加工 (Processor) し、目的のバックエンドへ送出する (Exporter) 役割を担う。
2026 年現在、OpenTelemetry は事実上、可観測性の計測における業界標準になった。Jaeger v2 は内部的に OpenTelemetry Collector ベースへ再設計され、Zipkin Exporter は 2025 年から公式に廃止予定 (Deprecated) の状態へ移行した。この流れの中で Collector の正しい運用方法を理解することは、プラットフォームエンジニアと SRE にとって中核的な能力である。
この記事では、OpenTelemetry Collector のアーキテクチャ、パイプライン設定、さまざまなバックエンドとの連携、Kubernetes デプロイ戦略、サンプリング手法、パフォーマンスチューニング、トラブルシューティング、障害復旧まで、運用に必要な内容をすべて実践的な例とともに総まとめする。
OpenTelemetry のアーキテクチャと Collector の役割
全体アーキテクチャの概要
OpenTelemetry フレームワークは大きく三つのレイヤーで構成される。
- SDK/API レイヤー: 各言語の SDK がアプリケーションコードでテレメトリデータを生成する。
- Collector レイヤー: 生成されたテレメトリデータを受信、加工、ルーティングする。
- Backend レイヤー: 最終的な保存先 (Jaeger、Tempo、Datadog など) でデータを保存し可視化する。
[アプリケーション + OTel SDK]
|
| OTLP (gRPC/HTTP)
v
+========================+
| OpenTelemetry |
| Collector |
| |
| Receiver -> Processor |
| -> Exporter |
+========================+
| | |
v v v
[Jaeger] [Tempo] [Datadog]
Collector はこのアーキテクチャで中央ハブの役割を果たす。アプリケーションは OTLP (OpenTelemetry Protocol) でデータを送信するだけでよく、どのバックエンドを使うかは Collector の設定で決める。これによりバックエンドを入れ替える際も、アプリケーションコードを変更せず Collector の設定だけ修正すればよい。
Core と Contrib のディストリビューション
OpenTelemetry Collector は二つのディストリビューションを提供する。
| 項目 | Core | Contrib |
|---|---|---|
| コンポーネント範囲 | 主要な Receiver/Processor/Exporter のみ | コミュニティ提供コンポーネントを多数含む |
| バイナリサイズ | 約 50MB | 約 200MB 以上 |
| セキュリティ露出面 | 小さい | 広い |
| 適した環境 | カスタムビルドを前提としたプロダクション | PoC、テスト、導入初期 |
プロダクション環境では、OpenTelemetry Collector Builder (OCB) を使って必要なコンポーネントだけを含むカスタムバイナリをビルドすることが、セキュリティとリソース効率の両面から推奨される。
分散トレーシングツールの比較: OpenTelemetry / Jaeger / Zipkin
Collector の構成を扱う前に、主要な分散トレーシングツールの位置づけの変化を先に整理する。
| 項目 | OpenTelemetry | Jaeger | Zipkin |
|---|---|---|---|
| プロジェクト状態 | CNCF Graduated (活発に開発中) | CNCF Graduated (v2 への移行完了) | 独立プロジェクト (メンテナンスモード) |
| 主要言語 | Go (Collector)、多言語 SDK | Go | Java |
| 役割 | 計測フレームワーク + 収集パイプライン | トレースの保存/クエリ/可視化バックエンド | トレースの保存/クエリ/可視化バックエンド |
| プロトコル | OTLP (gRPC、HTTP/protobuf) | OTLP、Thrift (Legacy) | HTTP/JSON、Thrift |
| テレメトリ範囲 | Traces + Metrics + Logs | Traces のみ | Traces のみ |
| Kubernetes 対応 | Operator、Helm Chart、DaemonSet/Deployment | Helm Chart、Operator | Helm Chart |
| バックエンド連携 | ベンダーニュートラル (すべてのバックエンドに対応) | 自前 UI + Elasticsearch/Cassandra/ClickHouse | 自前 UI + Elasticsearch/Cassandra |
| サンプリング | Head-based + Tail-based (Collector) | Remote Sampling API | 確率的サンプリング |
| 2026 年の推奨 | 計測の標準として使用 | OTLP ベースの v2 への移行を推奨 | 新規導入は非推奨 (Deprecated 予定) |
要点をまとめると、OpenTelemetry は計測と収集の標準、Jaeger v2 は OTLP ネイティブのバックエンド、Zipkin はレガシー移行の対象である。2025 年から OpenTelemetry SDK の Zipkin Exporter が公式に廃止予定へ移行したため、新規プロジェクトでは OTLP ベースのアーキテクチャを採用するのが望ましい。
Receiver-Processor-Exporter パイプラインの構成
パイプライン構造の理解
OpenTelemetry Collector の設定ファイルは四つの最上位セクションで構成される。
- receivers: データの受信方法を定義
- processors: データの加工/変換/フィルタリングのルールを定義
- exporters: データの送信先を定義
- service: 上のコンポーネントを組み合わせて実際のパイプラインを有効化
重要な点は、receivers、processors、exporters の各セクションでコンポーネントを定義しても、service.pipelines で参照しなければ有効にならないということだ。
基本的なパイプライン設定の例
次は OTLP Receiver でトレースを受信し、バッチ処理のあとに OTLP Exporter へ送信する基本的な設定である。
# otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
memory_limiter:
check_interval: 1s
limit_mib: 512
spike_limit_mib: 128
batch:
send_batch_size: 8192
timeout: 200ms
send_batch_max_size: 0
exporters:
otlp:
endpoint: tempo.monitoring.svc.cluster.local:4317
tls:
insecure: true
debug:
verbosity: detailed
extensions:
health_check:
endpoint: 0.0.0.0:13133
zpages:
endpoint: 0.0.0.0:55679
service:
extensions: [health_check, zpages]
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp, debug]
この設定で核心となるのはプロセッサーの順序である。memory_limiter は常に最初のプロセッサーとして配置しなければならない。メモリ制限を超えた時点でデータを早めに拒否し、Collector の OOM (Out of Memory) クラッシュを防ぐためだ。batch は必ず memory_limiter とサンプリングプロセッサーの後ろに配置し、データのドロップが完了したあとにバッチを構成する必要がある。
Receiver の詳細設定
OTLP Receiver
最も基本的で推奨される Receiver である。gRPC (4317) と HTTP (4318) の二つのプロトコルをサポートする。
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
max_recv_msg_size_mib: 4
keepalive:
server_parameters:
max_connection_idle: 11s
max_connection_age: 30s
http:
endpoint: 0.0.0.0:4318
cors:
allowed_origins:
- 'https://*.example.com'
Jaeger Receiver
レガシーな Jaeger クライアントとの互換性のために使う。Jaeger v2 への移行の過渡期に有用である。
receivers:
jaeger:
protocols:
grpc:
endpoint: 0.0.0.0:14250
thrift_http:
endpoint: 0.0.0.0:14268
thrift_compact:
endpoint: 0.0.0.0:6831
Prometheus Receiver
Prometheus のスクレイピング方式でメトリクスを収集する。Kubernetes のサービスディスカバリと連携できる。
receivers:
prometheus:
config:
scrape_configs:
- job_name: 'otel-collector-internal'
scrape_interval: 15s
static_configs:
- targets: ['0.0.0.0:8888']
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+)
replacement: $$1
Processor の詳細設定
Memory Limiter Processor
Collector のメモリ使用量を制御して OOM クラッシュを防ぐ必須のプロセッサーである。すべてのパイプラインで最初のプロセッサーとして配置しなければならない。
processors:
memory_limiter:
check_interval: 1s
limit_mib: 1024 # ハードリミット (1GB)
spike_limit_mib: 256 # スパイク許容値 (ハードリミットの約 20%)
設定値の算定ガイド:
limit_mib: コンテナのメモリ制限のおよそ 80% に設定する。コンテナのメモリ制限が 2GB ならlimit_mib: 1638程度が適切だ。spike_limit_mib:limit_mibの約 20% に設定する。ソフトリミットはlimit_mib - spike_limit_mibで計算される。GOMEMLIMIT環境変数: Collector コンテナのGOMEMLIMITをハードリミットの 80% (つまりコンテナのメモリ制限の約 64%) に設定すると、Go ランタイムの GC がより効率的に動作する。
Batch Processor
テレメトリデータをバッチにまとめてネットワークリクエストの回数を減らし、シリアライズの CPU オーバーヘッドを下げるプロセッサーである。
processors:
batch:
send_batch_size: 8192 # この件数に達したら即座に送信
timeout: 200ms # サイズに関係なくこの時間が過ぎたら送信
send_batch_max_size: 16384 # バッチ最大サイズの上限 (0 なら無制限)
send_batch_sizeはトリガーの役割であって、バッチサイズの上限ではない。実際のバッチサイズを制限するにはsend_batch_max_sizeを必ず設定する必要がある。- メモリ圧迫があるときは
send_batch_sizeとtimeoutを小さくして、バッチをより早くフラッシュする。
Filter Processor
不要なテレメトリデータを早い段階でドロップし、バックエンドのコストを削減する。
processors:
filter:
error_mode: ignore
traces:
span:
- 'attributes["http.route"] == "/healthz"'
- 'attributes["http.route"] == "/readyz"'
- 'name == "health_check"'
metrics:
metric:
- 'name == "rpc.server.duration" and resource.attributes["service.name"] == "debug-svc"'
上の設定はヘルスチェックのパスのトレースと、特定サービスの不要なメトリクスをフィルタリングし、バックエンドへ送信しない。高トラフィックの環境ではテレメトリのコストを大きく削減できる。
Attributes Processor
スパンやメトリクスに属性を追加、修正、削除するプロセッサーである。
processors:
attributes:
actions:
- key: environment
value: production
action: upsert
- key: db.statement
action: delete
- key: http.request.header.authorization
action: delete
機微情報 (DB クエリ、認証トークンなど) を削除する用途に特に有用だ。
さまざまなバックエンドとの連携
Jaeger (OTLP)
Jaeger v2 は OTLP をネイティブにサポートするため、専用の Jaeger Exporter ではなく OTLP Exporter を使う。
exporters:
otlp/jaeger:
endpoint: jaeger-collector.monitoring.svc.cluster.local:4317
tls:
insecure: true
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
sending_queue:
enabled: true
num_consumers: 10
queue_size: 5000
Grafana Tempo
Tempo も OTLP をネイティブにサポートする。gRPC または HTTP のプロトコルを選択できる。
exporters:
otlp/tempo:
endpoint: tempo-distributor.monitoring.svc.cluster.local:4317
tls:
insecure: true
sending_queue:
enabled: true
num_consumers: 10
queue_size: 10000
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
Datadog
Datadog Exporter は collector-contrib に含まれており、API Key で認証する。
exporters:
datadog:
api:
key: ${env:DD_API_KEY}
site: datadoghq.com
traces:
span_name_as_resource_name: true
metrics:
histograms:
mode: distributions
sending_queue:
enabled: true
num_consumers: 10
queue_size: 5000
マルチバックエンドのパイプライン構成
一つの Collector から複数のバックエンドへ同時にデータを送信する構成である。
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, filter, attributes, batch]
exporters: [otlp/tempo, datadog]
metrics:
receivers: [otlp, prometheus]
processors: [memory_limiter, batch]
exporters: [prometheusremotewrite]
logs:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [loki]
各 Exporter はデータのコピーを受け取るため、一つの Exporter の障害が別の Exporter に影響しない。ただし、すべての Exporter が同じデータを処理するので、Receiver と Processor の負荷は共有される。
Kubernetes 環境でのデプロイ戦略
DaemonSet と Deployment
Kubernetes 環境で Collector をデプロイする主要なパターンは二つある。
| 項目 | DaemonSet (Agent) | Deployment (Gateway) |
|---|---|---|
| デプロイ単位 | すべてのノードに 1 つずつ | 指定した Replica 数だけ |
| 役割 | ローカルのテレメトリ収集、一次加工 | 中央集約処理、集計、最終送信 |
| ネットワーク負荷 | ノード内通信 (低い) | ノード間通信 (高い) |
| Tail Sampling | 不適 (トレースが分散する) | 適する (すべてのスパンが集まる) |
| クラスタメトリクス | 収集時にデータ重複のリスク | 重複なく収集できる |
| 障害の影響範囲 | 該当ノードのみ | パイプライン全体 |
| スケーリング | ノード追加時に自動 | HPA による手動/自動スケーリング |
プロダクションで推奨されるパターンは DaemonSet (Agent) + Deployment (Gateway) の階層構造である。Agent が各ノードでローカル収集と一次加工を行い、Gateway が集計、Tail Sampling、最終的なバックエンドへの送信を担当する。
DaemonSet Agent マニフェスト
# otel-agent-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: otel-collector-agent
namespace: monitoring
spec:
selector:
matchLabels:
app: otel-collector-agent
template:
metadata:
labels:
app: otel-collector-agent
spec:
containers:
- name: otel-collector
image: otel/opentelemetry-collector-contrib:0.120.0
args: ['--config=/etc/otelcol/config.yaml']
env:
- name: GOMEMLIMIT
value: '400MiB'
- name: K8S_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
ports:
- containerPort: 4317 # OTLP gRPC
hostPort: 4317
protocol: TCP
- containerPort: 4318 # OTLP HTTP
hostPort: 4318
protocol: TCP
- containerPort: 13133 # Health Check
protocol: TCP
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /
port: 13133
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 13133
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: config
mountPath: /etc/otelcol
volumes:
- name: config
configMap:
name: otel-agent-config
Gateway Deployment マニフェスト
# otel-gateway-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-collector-gateway
namespace: monitoring
spec:
replicas: 3
selector:
matchLabels:
app: otel-collector-gateway
template:
metadata:
labels:
app: otel-collector-gateway
spec:
containers:
- name: otel-collector
image: otel/opentelemetry-collector-contrib:0.120.0
args: ['--config=/etc/otelcol/config.yaml']
env:
- name: GOMEMLIMIT
value: '3200MiB'
ports:
- containerPort: 4317
protocol: TCP
- containerPort: 13133
protocol: TCP
resources:
requests:
cpu: 1000m
memory: 2Gi
limits:
cpu: 2000m
memory: 4Gi
livenessProbe:
httpGet:
path: /
port: 13133
readinessProbe:
httpGet:
path: /
port: 13133
volumeMounts:
- name: config
mountPath: /etc/otelcol
volumes:
- name: config
configMap:
name: otel-gateway-config
---
apiVersion: v1
kind: Service
metadata:
name: otel-collector-gateway
namespace: monitoring
spec:
selector:
app: otel-collector-gateway
ports:
- name: otlp-grpc
port: 4317
targetPort: 4317
- name: otlp-http
port: 4318
targetPort: 4318
type: ClusterIP
Agent の設定では Gateway Service を Exporter のエンドポイントとして指定する。
# Agent の exporter 設定
exporters:
otlp/gateway:
endpoint: otel-collector-gateway.monitoring.svc.cluster.local:4317
tls:
insecure: true
sending_queue:
enabled: true
queue_size: 2000
retry_on_failure:
enabled: true
Gateway への接続は必ず Kubernetes Service 経由で行う必要がある。Pod IP を直接参照すると Pod の再起動時に接続が切れ、ロードバランシングも行われない。
サンプリング戦略
Head-based Sampling
SDK のレベルでトレース開始時点にサンプリングの判断を下す方式である。
利点: 実装が単純で、リソースの節約が即座に効く。
欠点: トレース全体を見ずに判断するため、エラーを含むトレースを取りこぼす可能性がある。
# SDK 設定で TraceIdRatioBased Sampler を使用
# トレースの 10% だけをサンプリング
processors:
probabilistic_sampler:
sampling_percentage: 10
Tail-based Sampling
トレースのすべての (またはほとんどの) スパンが到着したあとにサンプリングの判断を下す方式である。Collector の Tail Sampling Processor で実施する。
利点: エラーや高レイテンシなど、特定の条件を満たすトレースを 100% 保存できる。
欠点: トレースのすべてのスパンが一箇所に集まる必要があるため Gateway Collector でのみ使うべきであり、メモリ消費が大きい。
processors:
tail_sampling:
decision_wait: 30s
num_traces: 100000
expected_new_traces_per_sec: 1000
policies:
# ポリシー 1: エラーを含むトレースは 100% サンプリング
- name: errors-policy
type: status_code
status_code:
status_codes:
- ERROR
# ポリシー 2: レイテンシが 500ms を超えるトレースは 100% サンプリング
- name: latency-policy
type: latency
latency:
threshold_ms: 500
# ポリシー 3: 残りのトレースは 5% のみサンプリング
- name: probabilistic-policy
type: probabilistic
probabilistic:
sampling_percentage: 5
Tail Sampling 運用時の注意点:
- DaemonSet Agent では絶対に使わない。トレースのスパンが複数のノードに分散して到着するため、各 Agent はトレースの一部しか見られず、正しいサンプリングの判断を下せない。
decision_waitは、トレースのすべてのスパンが到着するための時間的な余裕を意味する。短すぎると不完全なトレースを元に判断し、長すぎるとメモリ消費が急増する。num_tracesは同時にメモリへ保持するトレース数の上限である。これを超えると最も古いトレースが強制的に判断される。
推奨するサンプリング戦略の組み合わせ
| 環境 | 推奨する戦略 | 説明 |
|---|---|---|
| トラフィックが少ないサービス | 全量収集 (100%) | すべてのトレースを保存しデバッグしやすくする |
| 一般的なプロダクション | Head 10% + Tail エラー/遅延 | コスト削減と重要トレース保存のバランス |
| 高トラフィックのサービス | Head 1% + Tail エラー/遅延 | 大量トラフィックでのコスト最適化 |
| 規制/監査の対象 | 全量収集 + 長期保存 | コンプライアンス要件を満たす |
パフォーマンスチューニングと高可用性の構成
主要なパフォーマンスパラメータ
# パフォーマンス最適化の設定例
processors:
memory_limiter:
check_interval: 1s
limit_mib: 1638 # コンテナメモリ 2GB の ~80%
spike_limit_mib: 328 # limit_mib の ~20%
batch:
send_batch_size: 10000
timeout: 500ms
send_batch_max_size: 20000
exporters:
otlp/backend:
endpoint: backend:4317
sending_queue:
enabled: true
num_consumers: 20 # 並列送信ワーカー数
queue_size: 10000 # キューサイズ (バッチ単位)
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
timeout: 30s
GOMEMLIMIT の設定
Go ランタイムの GC 効率を高めるために GOMEMLIMIT 環境変数を設定する。
# コンテナのメモリ制限が 2GB のとき
# GOMEMLIMIT = limit_mib * 0.8 = 1638 * 0.8 ~ 1310MiB
export GOMEMLIMIT=1310MiB
| コンテナメモリ | limit_mib | spike_limit_mib | GOMEMLIMIT |
|---|---|---|---|
| 512Mi | 410 | 82 | 328MiB |
| 1Gi | 820 | 164 | 656MiB |
| 2Gi | 1638 | 328 | 1310MiB |
| 4Gi | 3276 | 655 | 2621MiB |
高可用性 (HA) の構成
Gateway Collector の高可用性のための主要な戦略は以下の通りだ。
- 最低 3 つの Replica: Deployment の replicas を最低 3 に設定する。
- Pod Anti-Affinity: 同一ノードに Gateway Pod が集中しないよう設定する。
- PDB (PodDisruptionBudget): 同時に終了する Pod 数を制限する。
- HPA: CPU/メモリベースの自動スケーリングを構成する。
# PodDisruptionBudget の設定
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: otel-gateway-pdb
namespace: monitoring
spec:
minAvailable: 2
selector:
matchLabels:
app: otel-collector-gateway
トラブルシューティングガイド
よくある問題と解決方法
1. データがバックエンドに到達しない場合
# 1 段階: Collector のログを確認
kubectl logs -n monitoring deploy/otel-collector-gateway --tail=100
# 2 段階: zPages でパイプラインの状態を確認
kubectl port-forward -n monitoring svc/otel-collector-gateway 55679:55679
# ブラウザで http://localhost:55679/debug/tracez にアクセス
# 3 段階: debug exporter を一時的に追加してデータの流れを確認
# exporters に debug: { verbosity: detailed } を追加したあと
# pipeline に debug exporter を追加
2. Collector のメモリ使用量が急増
memory_limiterが設定されているか確認する。GOMEMLIMITが適切に設定されているか確認する。- Tail Sampling の
num_tracesの値が大きすぎないか確認する。 - Exporter の
sending_queue.queue_sizeが過大でないか確認する。
3. Exporter キューの飽和
# Collector の内部メトリクスでキューの状態を確認
curl http://localhost:8888/metrics | grep otelcol_exporter_queue
# otelcol_exporter_queue_size: 現在のキューサイズ
# otelcol_exporter_queue_capacity: キューの最大容量
# queue_size が capacity に近づいたらキュー飽和の状態
原因: バックエンドがデータを十分な速さで処理できていないか、Collector に過度なトラフィックが流入している。
解決: num_consumers を増やす、バックエンドの処理能力を確認する、フィルタープロセッサーで不要なデータを早期にドロップする、といった対処を行う。
4. プロセッサー順序の誤り
誤ったプロセッサーの順序は微妙な問題を引き起こす。
| よくある間違い | 症状 | 正しい順序 |
|---|---|---|
| batch を memory_limiter の前に配置 | メモリ急増のあと OOM | memory_limiter を常に最初に |
| attributes を batch の後ろに配置 | 属性の変更が適用されない | attributes は batch の前に |
| tail_sampling を DaemonSet に配置 | 不完全なサンプリング判断 | tail_sampling は Gateway でのみ使う |
| resourcedetection を最後に配置 | リソース属性が欠落する | resourcedetection は前方に配置 |
主要な監視メトリクス
Collector 自体の運用状態を監視するために、次の内部メトリクスを追跡する必要がある。
| メトリクス | 説明 | アラート基準 |
|---|---|---|
otelcol_receiver_accepted_spans | 受信に成功したスパン数 | 急激に減少したらアラート |
otelcol_receiver_refused_spans | 受信を拒否したスパン数 | 0 以外の値が続いたらアラート |
otelcol_exporter_sent_spans | 送信に成功したスパン数 | accepted と大きく差が出たらアラート |
otelcol_exporter_send_failed_spans | 送信に失敗したスパン数 | 0 以外の値が続いたらアラート |
otelcol_exporter_queue_size | 現在のキューサイズ | capacity の 80% を超えたらアラート |
otelcol_processor_dropped_spans | プロセッサーでドロップされたスパン | 想定を超えたらアラート |
障害事例と復旧手順
事例 1: Gateway の全面障害 (全 Replica ダウン)
症状: すべてのテレメトリデータが失われる。Agent の Exporter キューが飽和し、データのドロップが始まる。
原因: 誤った設定変更のデプロイ、OOM の連鎖発生、Node 障害など。
復旧手順:
- ただちに以前の正常な ConfigMap へロールバックする。
- Gateway Deployment の replicas が十分か確認する。
- Pod Anti-Affinity が設定されているか検証する。
- Agent 側の sending_queue と retry_on_failure の設定を確認する。キューに溜まったデータは Gateway の復旧後に自動で再送される。
- 再発防止のため PDB を設定し、ConfigMap の変更時には Canary デプロイを適用する。
# ConfigMap のロールバック
kubectl rollout undo configmap/otel-gateway-config -n monitoring
# または以前のバージョンの ConfigMap を直接適用
kubectl apply -f otel-gateway-config-backup.yaml
# Gateway Deployment の再起動
kubectl rollout restart deployment/otel-collector-gateway -n monitoring
# 復旧状態の確認
kubectl rollout status deployment/otel-collector-gateway -n monitoring
事例 2: バックエンド障害によるデータ欠損
症状: Exporter キューの飽和、otelcol_exporter_send_failed_spans の急増。
原因: バックエンド (Tempo、Jaeger など) がダウンする、あるいは応答が遅くなる。
復旧手順:
- まずバックエンドの状態を確認して復旧する。
- Collector は retry_on_failure の設定によって自動で再試行する。
- キュー飽和でドロップされたデータは復旧できないため、長期的にはキューサイズを増やすか、Kafka などのバッファ層を導入する。
事例 3: memory_limiter 未設定による OOM
症状: Collector Pod が OOMKilled の状態で再起動を繰り返す。
原因: memory_limiter プロセッサーの未設定、または不適切な値の設定。
復旧手順:
- memory_limiter をすべてのパイプラインの最初のプロセッサーとして追加する。
- limit_mib をコンテナのメモリ制限の 80% に設定する。
- GOMEMLIMIT 環境変数を設定する。
- コンテナのリソース制限がワークロードに対して小さすぎないか検討する。
運用チェックリスト
初期デプロイのチェックリスト
- memory_limiter プロセッサーがすべてのパイプラインの最初のプロセッサーに設定されているか
- GOMEMLIMIT 環境変数が設定されているか
- health_check Extension が有効になっているか
- livenessProbe と readinessProbe が設定されているか
- Exporter で sending_queue と retry_on_failure が有効になっているか
- コンテナのリソース requests/limits が適切に設定されているか
- PodDisruptionBudget が設定されているか
プロセッサー順序のチェックリスト
- memory_limiter が最初のプロセッサーか
- resourcedetection が memory_limiter の次に位置しているか (使用する場合)
- filter/attributes などのデータ加工プロセッサーが batch の前に位置しているか
- tail_sampling が Gateway でのみ使われているか (使用する場合)
- batch が最後のプロセッサーか
モニタリングのチェックリスト
- Collector の内部メトリクス (8888 ポート) を Prometheus で収集しているか
- Exporter のキュー飽和アラートが設定されているか
- 受信拒否 (refused) メトリクスのアラートが設定されているか
- 送信失敗 (send_failed) メトリクスのアラートが設定されているか
- Collector Pod のメモリ/CPU 使用量のアラートが設定されているか
セキュリティのチェックリスト
- 不要なポートが外部に公開されていないか
- TLS が必要な通信経路に適用されているか
- API Key などの機微情報が環境変数または Secret で管理されているか
- attributes プロセッサーで機微な属性 (DB クエリ、認証トークン) を削除しているか
おわりに
OpenTelemetry Collector は現代的な可観測性パイプラインの中核インフラである。ベンダーニュートラルな設計のおかげで、Jaeger、Grafana Tempo、Datadog などどのバックエンドとも柔軟に連携でき、バックエンドを入れ替える際もアプリケーションコードを修正する必要がない。
安定した運用のために最も重要な三つをまとめると以下の通りだ。
- memory_limiter を必ず最初のプロセッサーに設定し、GOMEMLIMIT を適切に構成する。
- DaemonSet (Agent) + Deployment (Gateway) の階層構造でデプロイし、ローカル収集と中央集約処理を分離する。
- Exporter の sending_queue と retry_on_failure を有効化し、一時的なバックエンド障害への回復力を確保する。
Collector は継続的に進化しており、OpAMP (Open Agent Management Protocol) による遠隔設定管理など、新しい機能が次々と追加されている。公式ドキュメントとリリースノートを定期的に確認し、最新の変更を反映するのが望ましい。
参考資料
- OpenTelemetry Collector 公式ドキュメント
- OpenTelemetry Collector Configuration
- OpenTelemetry Collector Architecture
- OpenTelemetry Sampling の概念
- OpenTelemetry Collector Scaling Guide
- OpenTelemetry Collector Troubleshooting
- OpenTelemetry Kubernetes Helm Chart
- Tail Sampling Processor (GitHub)
- Memory Limiter Processor (GitHub)
- Batch Processor (GitHub)