2026年7月1日
2026年7月1日
KubernetesでOpenTelemetryの分散トレーシングを始める|Collectorの配置・自動計装・サンプリング
Kubernetesで分散トレーシングを始めるには、アプリがOpenTelemetry(OTel)の形式でトレースを出し、クラスター内のOpenTelemetry Collectorがそれを受け取って保存先に送る、という構成を作ります。アプリが保存先を直接知る必要がなくなり、Podの情報(名前空間やDeployment名)もCollector側で付けられます。この記事では、Collectorの置き方(DaemonSetとゲートウェイ)、設定ファイルの書き方、アプリから送る方法(自動計装と環境変数)、WordPress(PHP)の場合、サンプリングの考え方を説明します。
OpenTelemetryは開発が活発で、Collectorの設定項目やHelmチャートの値、言語ごとの対応状況は版によって変わります。この記事の内容は2026年10月現在の情報をもとにした例なので、導入時は公式ドキュメントと各リポジトリのリリースノートを確認してください。
分散トレーシングで分かること
1つのリクエストがIngress、WordPress、外部API、データベースと渡っていくとき、どこで何ミリ秒かかったかを1本のタイムラインで見られるのが分散トレーシングです。1つのリクエスト全体を「トレース」、その中の各処理を「スパン」と呼びます。
サービスをまたいでスパンをつなげるには、トレースIDを次のサービスに引き継ぐ必要があります。OpenTelemetryでは既定でW3C Trace Contextの traceparent ヘッダーを使います。途中にあるプロキシやアプリがこのヘッダーを捨ててしまうと、トレースがそこで途切れます。
構成の全体像
基本の構成は次の3層です。
- アプリ:OpenTelemetryのSDKや自動計装でスパンを作り、OTLP(OpenTelemetry Protocol)で送る。ポートは gRPC が4317、HTTP が4318。
- Collector:受け取ったデータに情報を付け、まとめて保存先に送る。
- 保存先(バックエンド):Jaeger、Grafana Tempo、各社のオブザーバビリティサービスなど。多くがOTLPを直接受け付けます。
Collectorの置き方には2つの型があります。
- エージェント(DaemonSet):各ノードに1つずつ置き、同じノードのPodから受け取る。Podの情報を付けやすく、ノード内で通信が完結する。
- ゲートウェイ(Deployment):クラスターに数台だけ置き、全体のデータを集めて送る。サンプリングや送信先の認証情報の管理を1か所にまとめられる。
小さく始めるならゲートウェイだけでも動きます。規模が大きくなったら、エージェントで受けてゲートウェイに集める2段構成にします。
Collectorを入れる
Collectorは、OpenTelemetryの公式Helmチャートで入れるのが手軽です。
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo update
helm install otel-gateway open-telemetry/opentelemetry-collector \
-n observability --create-namespace -f values.yaml
values.yaml ではモード(deployment、daemonset など)と、使うイメージを指定します。Collectorには機能の少ない標準版と、多くの部品を含む contrib 版、Kubernetes向けの k8s 版といった配布物があり、使いたいプロセッサーが含まれている配布物を選びます。
# values.yaml(例)
mode: deployment
replicaCount: 2
image:
repository: otel/opentelemetry-collector-k8s
config:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
memory_limiter:
check_interval: 1s
limit_percentage: 80
spike_limit_percentage: 25
k8sattributes: {}
batch: {}
exporters:
otlp:
endpoint: tempo.observability.svc.cluster.local:4317
tls:
insecure: true # クラスター内の検証用。本番ではTLSを設定する
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, k8sattributes, batch]
exporters: [otlp]
設定は「受け取る(receivers)」「加工する(processors)」「送る(exporters)」を service.pipelines でつなぐ形です。定義しただけでパイプラインに書いていない部品は使われません。
つまずきやすい点が3つあります。
- 待ち受けのアドレス:最近のCollectorはreceiverの既定の待ち受けが
localhostになっているため、0.0.0.0を明示しないとほかのPodから届きません。 - プロセッサーの順番:
memory_limiterは先頭に置きます。Collectorのメモリ不足によるPodの再起動を防ぐためです。Pod側のresources.limits.memoryも設定しておきます。 - k8sattributes の権限:Podの情報を引くために、Pod・名前空間・ReplicaSetなどを読むRBACの権限が必要です。Helmチャートには、この権限をまとめて作る設定(プリセット)が用意されています。
送信がうまくいかないときは、exporters に debug を追加してパイプラインに入れると、受け取ったスパンがCollectorのログに出ます。Collectorまで届いているのか、保存先への送信で失敗しているのかを切り分けられます。
アプリからトレースを送る
環境変数で送信先を決める
OpenTelemetryのSDKは、言語をまたいで共通の環境変数で設定できます。Deploymentに次のように書くと、コードを変えずに送信先やサービス名を切り替えられます。
env:
- name: OTEL_SERVICE_NAME
value: wordpress
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://otel-gateway-opentelemetry-collector.observability.svc.cluster.local:4318
- name: OTEL_EXPORTER_OTLP_PROTOCOL
value: http/protobuf
- name: OTEL_PROPAGATORS
value: tracecontext,baggage
- name: OTEL_RESOURCE_ATTRIBUTES
value: deployment.environment=production
Serviceの名前(ここではHelmのリリース名から作られた名前)は環境によって変わるので、kubectl get svc -n observability で確認してください。DaemonSetのエージェントに送る場合は、Downward API の status.hostIP でノードのIPを環境変数に入れ、それを送信先に使う方法がよく使われます。
OpenTelemetry Operator の自動計装
OpenTelemetry Operator を入れると、Instrumentation というカスタムリソースと、Podへのアノテーションだけで計装用のライブラリを注入できます。Java、Node.js、Python、.NETなどの言語に対応しています。
metadata:
annotations:
instrumentation.opentelemetry.io/inject-python: "true"
Operatorはアドミッションwebhookを使うため、既定では証明書の管理に cert-manager が必要です。対応言語や注入の方式は版によって変わるので、Operatorのドキュメントで確認してください。
WordPress(PHP)の場合
PHPは、上記のOperatorによる自動注入の主な対象言語には含まれていません(2026年10月現在)。PHPでは、PECLの opentelemetry 拡張をイメージに入れ、Composerで SDK と OTLP のエクスポーター、自動計装のパッケージを追加する方法が一般的です。OpenTelemetryのPHP向けcontribリポジトリには、WordPress向けの自動計装パッケージも用意されています。
FROM wordpress:php8.3-apache
RUN pecl install opentelemetry && docker-php-ext-enable opentelemetry
PHPの自動計装を有効にするには、環境変数 OTEL_PHP_AUTOLOAD_ENABLED=true も設定します。Composerのパッケージ名と、WordPressのどの処理がスパンになるかは、パッケージの版ごとにREADMEで確認してください。WordPressのコアやプラグインのファイルを直接書き換える方法は、更新で消えるので避けます。導入後はまず検証環境で、ページの表示時間がどれだけ増えるかも測っておくと安心です。
サンプリングで量を抑える
すべてのリクエストのトレースを保存すると、保存先の容量と通信量が膨らみます。量を抑える方法は2つあります。
- ヘッドサンプリング:リクエストの最初に、保存するかどうかを確率で決める。SDKの環境変数で
OTEL_TRACES_SAMPLER=parentbased_traceidratio、OTEL_TRACES_SAMPLER_ARG=0.1とすると、おおよそ10件に1件を残します。軽い反面、エラーになったリクエストも同じ確率で捨てられます。 - テールサンプリング:トレースが終わってから、エラーや遅いリクエストを優先して残す。contrib 版などに含まれる
tail_samplingプロセッサーで行います。同じトレースのスパンが同じCollectorに集まる必要があるため、ゲートウェイを複数台にするときは、トレースIDで振り分ける構成(loadbalancingエクスポーター)を前段に置きます。
最初はヘッドサンプリングで始め、エラーの調査で困るようになったらテールサンプリングを検討する、という順番が無理のない進め方です。
まとめ
- アプリはOTLPでCollectorに送り、Collectorが情報を付けて保存先に送る。サービスをまたぐには
traceparentヘッダーの引き継ぎが必要。 - Collectorはゲートウェイだけでも始められ、規模に応じてDaemonSetのエージェントを足す。
- receiver は
0.0.0.0で待ち受け、memory_limiterを先頭に置き、k8sattributes にはRBACの権限を渡す。届かないときはdebugエクスポーターで切り分ける。 - 送信先やサービス名は共通の
OTEL_*環境変数で決める。PHPは拡張とComposerのパッケージで計装する。 - 量はヘッドサンプリングで抑え、必要に応じてテールサンプリングに進む。