Docker/Kubernetes環境でのOpenTelemetry構築
本番環境ではコンテナ化が前提となります。ここではOpenTelemetryをDocker、Docker Compose、そしてKubernetesで運用する方法を、段階的に学んでいきます。
Dockerでの基本的な運用
OpenTelemetryを含むアプリケーションをコンテナ化する際、Dockerfileは重要な役割を果たします。アプリケーションコンテナとOpenTelemetry Collectorを分離して運用するのが一般的なパターンです。
アプリケーションコンテナでは、OpenTelemetryライブラリをインストールし、Collectorのエンドポイント(通常は localhost:4317 など)を環境変数で指定します。重要なのは、各環境での設定値を環境変数として外部化することで、同じイメージを複数の環境で利用できるようにすることです。
環境変数の設定では、OTEL_EXPORTER_OTLP_ENDPOINTでCollectorの接続先を、OTEL_SERVICE_NAMEでサービス名を指定します。これらの値は実行時に上書き可能なため、開発環境と本番環境で異なる設定を運用できます。
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
ENV OTEL_SERVICE_NAME=my-app
ENV OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
CMD ["python", "app.py"]Docker Composeでのマルチコンテナ統合
複数のコンテナを一度に起動・管理する際、Docker Composeは大変便利です。アプリケーション、OpenTelemetry Collector、バックエンド(Jaegerなど)を同時に起動し、相互通信を自動的に設定できます。
Docker Composeではサービス間通信が自動的に解決されるため、Collectorのエンドポイントをサービス名で指定できます。例えば、otel-collectorというサービス名でCollectorを定義すれば、アプリケーションコンテナはhttp://otel-collector:4317で接続できます。
重要なポイントは、depends_onを使ってサービスの起動順序を制御し、Collectorが先に起動してから、アプリケーションが起動されるようにすることです。また、networksを明示的に定義することで、コンテナ間の通信をより明確に管理できます。
version: '3.8'
services:
app:
build: ./app
depends_on:
otel-collector:
condition: service_healthy
environment:
OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317
networks:
- otel-network
otel-collector:
image: otel/opentelemetry-collector:0.101.0
ports:
- "4317:4317"
- "4318:4318"
volumes:
- ./otel-collector-config.yaml:/etc/otel/config.yaml
command: ["--config=/etc/otel/config.yaml"]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:13133"]
interval: 10s
timeout: 5s
retries: 5
networks:
- otel-network
networks:
otel-network:
driver: bridgeKubernetesでの展開
Kubernetesの本番環境では、Deploymentを使ってアプリケーション(複数のPod)とOpenTelemetry Collectorを管理します。基本的な考え方はDocker Composeと同じですが、より細かい制御が可能です。
Deploymentではレプリケーション(複数のPodインスタンス)、ローリングアップデート、自動スケーリングなどが実装されます。アプリケーションのDeploymentでは、環境変数でOTELのエンドポイントを指定します。一方、Collectorは別のDeploymentで管理し、Kubernetesサービス経由でアクセスされます。
Kubernetes内ではDNS名解決が自動的に行われるため、otel-collector:4317というアドレスで接続できます。ServiceリソースはClusterIPタイプをデフォルトとするため、クラスタ内通信に適しています。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app:v1.0.0
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://otel-collector:4317"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: otel-collector-config
data:
config.yaml: |
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
exporters:
jaeger:
endpoint: jaeger:14250
service:
pipelines:
traces:
receivers: [otlp]
exporters: [jaeger]
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-collector
spec:
replicas: 1
template:
metadata:
labels:
app: otel-collector
spec:
containers:
- name: collector
image: otel/opentelemetry-collector:0.101.0
args: ["--config=/etc/otel/config.yaml"]
ports:
- containerPort: 4317
volumeMounts:
- name: otel-collector-config-vol
mountPath: /etc/otel
volumes:
- name: otel-collector-config-vol
configMap:
name: otel-collector-config
---
apiVersion: v1
kind: Service
metadata:
name: otel-collector
spec:
type: ClusterIP
selector:
app: otel-collector
ports:
- name: otlp-grpc
port: 4317
targetPort: 4317Helmチャートを使った効率的な導入
OpenTelemetry公式のHelmチャートを使うことで、Kubernetesへの導入がより簡単になります。複雑なマニフェスト作成や設定管理の手間を削減できるため、本番環境では推奨される方法です。
公式チャートはopen-telemetry/opentelemetry-collectorなどいくつかのバリエーションが提供されており、DaemonSet、Deployment、StatefulSetなど、用途に応じた展開モードを選択できます。DaemonSetは全ノードに配置するため、Node単位の監視に適しており、Deploymentはスケーラブルな統一的な収集に向いています。
Helmリポジトリを追加した後、簡単なコマンドでインストール可能です。values.yamlで設定をカスタマイズし、バックエンドのエンドポイントやリソース割り当てなどを調整します。
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo update
helm install otel-collector open-telemetry/opentelemetry-collector \
--values collector-values.yaml設定ファイルでは、レシーバー(何からデータを受け取るか)、プロセッサー(どう処理するか)、エクスポーター(どこに送るか)の三要素を定義します。Helmチャートではこれらをバリアブルで管理できるため、環境ごとの差異を簡単に吸収できます。
アーキテクチャ全体像
以下は、Docker Composeで複数コンテナを連携させた場合のアーキテクチャです。
Kubernetes環境ではさらに複雑になります。複数のノード上でPodが動作し、Serviceを経由してCollectorにアクセスします。
まとめへ向けて
Docker、Docker Compose、Kubernetesと段階的に複雑さが増していきますが、基本的な概念は変わりません。環境変数でエンドポイントを指定し、適切なネットワーク設定でコンテナ間通信を確立することが重要です。
本記事ではそれぞれの基本構成に焦点を当てました。次のステップとしては、実際の設定ファイルの詳細、バックエンドサービスへの接続設定、そしてトラブルシューティング手法を学ぶことで、より実践的な運用が可能になります。