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でサービス名を指定します。これらの値は実行時に上書き可能なため、開発環境と本番環境で異なる設定を運用できます。

dockerfile
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を明示的に定義することで、コンテナ間の通信をより明確に管理できます。

yaml
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: bridge

Kubernetesでの展開 ​

Kubernetesの本番環境では、Deploymentを使ってアプリケーション(複数のPod)とOpenTelemetry Collectorを管理します。基本的な考え方はDocker Composeと同じですが、より細かい制御が可能です。

Deploymentではレプリケーション(複数のPodインスタンス)、ローリングアップデート、自動スケーリングなどが実装されます。アプリケーションのDeploymentでは、環境変数でOTELのエンドポイントを指定します。一方、Collectorは別のDeploymentで管理し、Kubernetesサービス経由でアクセスされます。

Kubernetes内ではDNS名解決が自動的に行われるため、otel-collector:4317というアドレスで接続できます。ServiceリソースはClusterIPタイプをデフォルトとするため、クラスタ内通信に適しています。

yaml
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: 4317

Helmチャートを使った効率的な導入 ​

OpenTelemetry公式のHelmチャートを使うことで、Kubernetesへの導入がより簡単になります。複雑なマニフェスト作成や設定管理の手間を削減できるため、本番環境では推奨される方法です。

公式チャートはopen-telemetry/opentelemetry-collectorなどいくつかのバリエーションが提供されており、DaemonSet、Deployment、StatefulSetなど、用途に応じた展開モードを選択できます。DaemonSetは全ノードに配置するため、Node単位の監視に適しており、Deploymentはスケーラブルな統一的な収集に向いています。

Helmリポジトリを追加した後、簡単なコマンドでインストール可能です。values.yamlで設定をカスタマイズし、バックエンドのエンドポイントやリソース割り当てなどを調整します。

bash
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と段階的に複雑さが増していきますが、基本的な概念は変わりません。環境変数でエンドポイントを指定し、適切なネットワーク設定でコンテナ間通信を確立することが重要です。

本記事ではそれぞれの基本構成に焦点を当てました。次のステップとしては、実際の設定ファイルの詳細、バックエンドサービスへの接続設定、そしてトラブルシューティング手法を学ぶことで、より実践的な運用が可能になります。