OpenTelemetry
対応バージョン: OTEL 1.x 最終更新: July 13, 2026
はじめに
OpenTelemetry(OTel)は、クラウドネイティブソフトウェア向けの可観測性フレームワークです。Traces、Metrics、Logs という3つのシグナルを生成、収集、管理するためのベンダー中立な標準を提供します。CNCF で2番目に活発なプロジェクトとして、業界標準となっています。
OpenTelemetry とは?
OpenTelemetry は、OpenTracing プロジェクトと OpenCensus プロジェクトの統合から生まれました。
コアコンセプト
3つのシグナル
| シグナル | 説明 | ユースケース |
|---|---|---|
| Traces | 分散リクエストトレーシング | レイテンシー分析、依存関係マッピング |
| Metrics | 数値測定値 | リソース使用量、SLI/SLO |
| Logs | イベント記録 | デバッグ、監査 |
コアコンポーネント
OpenTelemetry SDK
自動計装
コードを変更せずに計装を自動的に追加します。
Java 自動計装
# Download Java Agent
curl -L -o opentelemetry-javaagent.jar \
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar# Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
template:
spec:
containers:
- name: app
image: order-service:latest
env:
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/opt/opentelemetry-javaagent.jar"
- name: OTEL_SERVICE_NAME
value: "order-service"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://otel-collector:4317"
- name: OTEL_EXPORTER_OTLP_PROTOCOL
value: "grpc"
- name: OTEL_TRACES_SAMPLER
value: "parentbased_traceidratio"
- name: OTEL_TRACES_SAMPLER_ARG
value: "0.1"
- name: OTEL_RESOURCE_ATTRIBUTES
value: "service.namespace=ecommerce,deployment.environment=production"
volumeMounts:
- name: otel-agent
mountPath: /opt/opentelemetry-javaagent.jar
subPath: opentelemetry-javaagent.jar
volumes:
- name: otel-agent
configMap:
name: otel-java-agentPython 自動計装
# Installation
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install# Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
spec:
template:
spec:
containers:
- name: app
image: payment-service:latest
command:
- opentelemetry-instrument
- python
- app.py
env:
- name: OTEL_SERVICE_NAME
value: "payment-service"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://otel-collector:4317"
- name: OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED
value: "true"Node.js 自動計装
// tracing.js
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-grpc');
const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');
const sdk = new NodeSDK({
serviceName: 'notification-service',
traceExporter: new OTLPTraceExporter({
url: 'http://otel-collector:4317',
}),
metricReader: new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter({
url: 'http://otel-collector:4317',
}),
exportIntervalMillis: 60000,
}),
instrumentations: [
getNodeAutoInstrumentations({
'@opentelemetry/instrumentation-fs': { enabled: false },
'@opentelemetry/instrumentation-http': {
ignoreIncomingRequestHook: (req) => req.url === '/health',
},
}),
],
});
sdk.start();
process.on('SIGTERM', () => {
sdk.shutdown().then(() => process.exit(0));
});手動計装
きめ細かな制御が必要な場合は、手動で計装します。
Java 手動計装
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
@Service
public class OrderService {
private final Tracer tracer;
public OrderService(OpenTelemetry openTelemetry) {
this.tracer = openTelemetry.getTracer("order-service", "1.0.0");
}
public Order processOrder(OrderRequest request) {
// Create parent span
Span parentSpan = tracer.spanBuilder("processOrder")
.setSpanKind(SpanKind.SERVER)
.setAttribute("order.id", request.getOrderId())
.setAttribute("customer.id", request.getCustomerId())
.startSpan();
try (Scope scope = parentSpan.makeCurrent()) {
// Business logic
parentSpan.addEvent("Order validation started");
// Child span - inventory check
Order order = checkInventory(request);
// Child span - payment processing
processPayment(order);
parentSpan.addEvent("Order processing completed");
parentSpan.setStatus(StatusCode.OK);
return order;
} catch (Exception e) {
parentSpan.setStatus(StatusCode.ERROR, e.getMessage());
parentSpan.recordException(e);
throw e;
} finally {
parentSpan.end();
}
}
private Order checkInventory(OrderRequest request) {
Span span = tracer.spanBuilder("checkInventory")
.setSpanKind(SpanKind.INTERNAL)
.startSpan();
try (Scope scope = span.makeCurrent()) {
span.setAttribute("product.count", request.getItems().size());
// Inventory check logic
Order order = inventoryService.check(request);
span.setAttribute("inventory.available", true);
return order;
} catch (InsufficientStockException e) {
span.setAttribute("inventory.available", false);
span.setStatus(StatusCode.ERROR, "Insufficient stock");
throw e;
} finally {
span.end();
}
}
}OTEL Collector
アーキテクチャ
Collector 設定
# otel-collector-config.yaml
receivers:
# OTLP receiver
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
max_recv_msg_size_mib: 16
http:
endpoint: 0.0.0.0:4318
cors:
allowed_origins:
- "http://*"
- "https://*"
# Jaeger compatibility
jaeger:
protocols:
thrift_http:
endpoint: 0.0.0.0:14268
grpc:
endpoint: 0.0.0.0:14250
# Zipkin compatibility
zipkin:
endpoint: 0.0.0.0:9411
processors:
# Memory limiter
memory_limiter:
check_interval: 1s
limit_mib: 1500
spike_limit_mib: 500
# Batch processing
batch:
timeout: 5s
send_batch_size: 1000
send_batch_max_size: 1500
# Add/modify attributes
attributes:
actions:
- key: environment
value: production
action: upsert
- key: cluster
value: eks-prod-cluster
action: upsert
# Resource detection
resourcedetection:
detectors: [env, system, ec2, eks]
timeout: 5s
override: false
# Filtering (exclude health checks)
filter:
error_mode: ignore
traces:
span:
- 'attributes["http.target"] == "/health"'
- 'attributes["http.target"] == "/ready"'
- 'attributes["http.target"] == "/metrics"'
# Tail Sampling (for traces)
tail_sampling:
decision_wait: 10s
num_traces: 100000
expected_new_traces_per_sec: 1000
policies:
# 100% collection for error requests
- name: error-policy
type: status_code
status_code:
status_codes: [ERROR]
# Collect slow requests
- name: latency-policy
type: latency
latency:
threshold_ms: 1000
# Priority collection for specific services
- name: service-priority
type: string_attribute
string_attribute:
key: service.name
values: [payment-service, order-service]
enabled_regex_matching: false
# Probabilistic sampling for the rest
- name: probabilistic-policy
type: probabilistic
probabilistic:
sampling_percentage: 10
exporters:
# OTLP (Tempo)
otlp/tempo:
endpoint: tempo-distributor.tempo.svc.cluster.local:4317
tls:
insecure: true
# AWS X-Ray
awsxray:
region: ap-northeast-2
index_all_attributes: true
# Prometheus Remote Write
prometheusremotewrite:
endpoint: http://prometheus:9090/api/v1/write
tls:
insecure: true
# Loki (logs)
loki:
endpoint: http://loki-gateway.loki.svc.cluster.local:3100/loki/api/v1/push
tls:
insecure: true
labels:
attributes:
service.name: "service"
service.namespace: "namespace"
k8s.pod.name: "pod"
extensions:
health_check:
endpoint: 0.0.0.0:13133
path: /health
pprof:
endpoint: 0.0.0.0:1777
service:
extensions: [health_check, pprof]
pipelines:
traces:
receivers: [otlp, jaeger, zipkin]
processors: [memory_limiter, resourcedetection, attributes, filter, tail_sampling, batch]
exporters: [otlp/tempo, awsxray]
metrics:
receivers: [otlp]
processors: [memory_limiter, resourcedetection, batch]
exporters: [prometheusremotewrite]
logs:
receivers: [otlp]
processors: [memory_limiter, resourcedetection, batch]
exporters: [loki]EKS Deployment パターン
DaemonSet パターン
各ノード上のすべての Pod からデータを収集するため、各ノードに Collector をデプロイします。
# otel-collector-daemonset.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: otel-collector
namespace: otel
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/otel-collector-role
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: otel-collector
namespace: otel
spec:
selector:
matchLabels:
app: otel-collector
template:
metadata:
labels:
app: otel-collector
spec:
serviceAccountName: otel-collector
containers:
- name: collector
image: otel/opentelemetry-collector-contrib:0.92.0
args:
- --config=/conf/otel-collector-config.yaml
ports:
- containerPort: 4317
hostPort: 4317
protocol: TCP
- containerPort: 4318
hostPort: 4318
protocol: TCP
env:
- name: K8S_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
resources:
requests:
cpu: 200m
memory: 400Mi
limits:
cpu: 1000m
memory: 1Gi
volumeMounts:
- name: config
mountPath: /conf
volumes:
- name: config
configMap:
name: otel-collector-config
tolerations:
- effect: NoSchedule
operator: Exists
---
apiVersion: v1
kind: Service
metadata:
name: otel-collector
namespace: otel
spec:
selector:
app: otel-collector
ports:
- name: otlp-grpc
port: 4317
protocol: TCP
- name: otlp-http
port: 4318
protocol: TCP
type: ClusterIPSidecar パターン
各アプリケーション Pod 内に Sidecar として Collector をデプロイします。
# application-with-sidecar.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
template:
spec:
containers:
# Application container
- name: app
image: order-service:latest
ports:
- containerPort: 8080
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://localhost:4317"
- name: OTEL_SERVICE_NAME
value: "order-service"
# OTEL Collector sidecar
- name: otel-collector
image: otel/opentelemetry-collector-contrib:0.92.0
args:
- --config=/conf/otel-collector-config.yaml
ports:
- containerPort: 4317
resources:
requests:
cpu: 50m
memory: 100Mi
limits:
cpu: 200m
memory: 200Mi
volumeMounts:
- name: otel-config
mountPath: /conf
volumes:
- name: otel-config
configMap:
name: otel-sidecar-configKubernetes Operator
OpenTelemetry Operator を使用した自動計装:
Operator のインストール
# Install cert-manager (required)
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml
# Install OpenTelemetry Operator
kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yamlInstrumentation CR
# instrumentation.yaml
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: otel-instrumentation
namespace: default
spec:
exporter:
endpoint: http://otel-collector.otel.svc.cluster.local:4317
propagators:
- tracecontext
- baggage
- b3
sampler:
type: parentbased_traceidratio
argument: "0.1"
# Java configuration
java:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:latest
env:
- name: OTEL_JAVAAGENT_DEBUG
value: "false"
# Python configuration
python:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-python:latest
env:
- name: OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED
value: "true"
# Node.js configuration
nodejs:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-nodejs:latest自動計装の注入
# Enable auto-instrumentation on namespace
apiVersion: v1
kind: Namespace
metadata:
name: ecommerce
annotations:
instrumentation.opentelemetry.io/inject-java: "true"
instrumentation.opentelemetry.io/inject-python: "true"
instrumentation.opentelemetry.io/inject-nodejs: "true"
---
# Or apply to individual Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: ecommerce
annotations:
instrumentation.opentelemetry.io/inject-java: "otel-instrumentation"
spec:
template:
metadata:
annotations:
# Pod-level annotation
instrumentation.opentelemetry.io/inject-java: "true"
spec:
containers:
- name: app
image: order-service:latestマルチバックエンド設定
単一の Collector から複数のバックエンドへデータを送信します。
exporters:
# Grafana Tempo
otlp/tempo:
endpoint: tempo-distributor:4317
tls:
insecure: true
# AWS X-Ray
awsxray:
region: ap-northeast-2
# Datadog
datadog:
api:
key: ${DD_API_KEY}
site: datadoghq.com
traces:
span_name_as_resource_name: true
# Jaeger
jaeger:
endpoint: jaeger-collector:14250
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp/tempo, awsxray, datadog, jaeger]2026年7月の更新: AI Agent トラフィックのネットワーク境界を観測する
CNCF のブログ記事では、NGINX と OpenTelemetry を使用して AI Agent 向けのネットワーク境界を構築するパターンを説明しています。AI Agent からのアウトバウンドトラフィックはフォワードプロキシ(NGINX)を経由するよう強制され、NGINX ネイティブ OpenTelemetry モジュールがリクエストごとに OTel span を出力します。これらの span は、上で説明したパイプラインと同様に OTel Collector を通過し、監査ログに永続化されるか、Jaeger、Grafana、または SIEM に転送されます。これにより、ユーザーインタラクションと Agent が代理で実行した外部呼び出しを関連付けられます。クラスターで Agent ワークロードを実行している場合、これは既存の OTel パイプラインをそのまま再利用できる有用な可観測性パターンです。
ベストプラクティス
1. Resource Attributes を標準化する
# Follow Semantic Conventions
resource:
attributes:
# Service information
service.name: order-service
service.version: 1.2.3
service.namespace: ecommerce
# Deployment environment
deployment.environment: production
# Cloud information
cloud.provider: aws
cloud.region: ap-northeast-2
cloud.availability_zone: ap-northeast-2a
# Kubernetes information
k8s.cluster.name: eks-prod
k8s.namespace.name: ecommerce
k8s.pod.name: order-service-abc123
k8s.deployment.name: order-service2. サンプリング戦略
# Hierarchical sampling
processors:
tail_sampling:
policies:
# Priority 1: 100% errors
- name: errors
type: status_code
status_code:
status_codes: [ERROR]
# Priority 2: 100% slow requests
- name: slow
type: latency
latency:
threshold_ms: 2000
# Priority 3: 50% critical services
- name: critical-services
type: and
and:
and_sub_policy:
- name: service-name
type: string_attribute
string_attribute:
key: service.name
values: [payment-service, order-service]
- name: probabilistic
type: probabilistic
probabilistic:
sampling_percentage: 50
# Priority 4: 5% for the rest
- name: default
type: probabilistic
probabilistic:
sampling_percentage: 53. セキュリティに関する考慮事項
# Enable TLS
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
tls:
cert_file: /certs/server.crt
key_file: /certs/server.key
exporters:
otlp:
endpoint: tempo:4317
tls:
ca_file: /certs/ca.crt
cert_file: /certs/client.crt
key_file: /certs/client.key
# Filter sensitive information
processors:
attributes:
actions:
- key: http.request.header.authorization
action: delete
- key: db.statement
action: hash # Hashingクイズ
OpenTelemetry クイズで理解度を確認しましょう。