DockerでSigNozをセルフホスト:Datadogの代替となるオープンソースAPM

Monitoring tutorial - IT technology blog
Monitoring tutorial - IT technology blog

問題:3つのツール、3つのダッシュボード、カオスな状況

自分のモニタリング環境はPrometheus + Grafanaで15台のサーバーを監視する構成だった。このセットアップはユーザーから報告が来る前に障害を検知するのに役立っていた——しかし、問題の一部しか解決できていなかった。具体的には、あるAPIエンドポイントが突然遅くなり始めたとき、デバッグの流れはこうなる:

  • GrafanaでCPU/RAMに問題がないか確認する
  • Jaegerを開いてdistributed tracesでリクエストの経路を追う
  • サーバーにSSHでログインしてgrepでエラーログを探す

3ステップ、3つのウィンドウ、連携していない3つのツール。問題が複雑だったからではなく、バラバラな断片から全体像を組み立てるのに時間がかかるせいで、デバッグに30〜40分費やしたことが何度もあった。

さらに、チームの誰かがDatadogを提案してきた。料金を見ると——$23/ホスト/月 × 15サーバー = $345/月——答えはノーだった。

本質:monitoring不足ではなく、observability不足

Monitoringobservabilityはまったく別物だ。Monitoringは何が起きているかを教えてくれる(CPU 90%など)。Observabilityはなぜ起きているかを教えてくれる——どのリクエストが原因か、どのサービスから来ているか、対応するエラーログは何か。

Observabilityの3本柱:

  • Metrics——時系列の統計データ(Prometheusが得意とする領域)
  • Traces——リクエストが各サービスを通過する経路(Jaeger、Zipkin)
  • Logs——イベントの詳細(Graylog、ELK)

この3つが別々のシステムに存在すると、それらを紐付ける作業は手動になる——そしてバグ修正そのものより時間がかかることが多い。SigNozはまさにこの痛点を解決する:3つをひとつのプラットフォームに統合し、あるtraceから対応するlogへ数秒でクリックして移動できる。

代替候補とSigNozを選んだ理由

SigNozを選ぶ前に、以下も検討した:

  • Grafana + Tempo + Loki:強力だが設定が複雑で、各パーツを手動でインテグレーションする必要がある
  • Jaeger単体:tracesのみで、metricsとlogsがない
  • Elastic APM:重い、RAMを大量消費、本番環境ではライセンスが複雑
  • SigNoz:OpenTelemetryネイティブ、単一のDocker Compose、UIが統合済み、オープンソース(AGPL)

決め手となったのは:SigNozがバックエンドストレージにElasticsearchではなくClickHouseを採用していること。ClickHouseは時系列データに最適化されており——数百万行のtraceに対するaggregationクエリが数倍高速で、同等のElastic stackと比べてRAM消費が約3〜5倍少ない。

ベストな方法:Docker ComposeでSigNozをセルフホストする

システム要件

  • RAM:最低4GB、推奨8GB
  • CPU:2コア以上
  • Disk:20GB以上(ClickHouseがtracesとlogsのデータを保存)
  • DockerとDocker Composeがインストール済みであること

ステップ1:リポジトリをクローンして起動する

# SigNozをクローン
git clone -b main https://github.com/SigNoz/signoz.git
cd signoz/deploy

# スタック全体を起動
docker compose -f docker/clickhouse-setup/docker-compose.yaml up -d

初回起動時に約2〜3GBのイメージをpullする。完了後、コンテナの状態を確認する:

docker compose -f docker/clickhouse-setup/docker-compose.yaml ps

# 期待される出力(すべて「Up」であること):
# signoz-frontend         Up
# signoz-query-service    Up
# signoz-otel-collector   Up
# clickhouse              Up
# zookeeper               Up

http://<server-ip>:3301でUIにアクセスできる。初回はadminアカウントの作成が求められる。

ステップ2:OpenTelemetryでSigNozにデータを送信する

SigNozはOpenTelemetry Collector経由でデータを受け取る——CNCFが開発したオープン標準だ。Python、Go、Java、Node.jsいずれもSDKが用意されている。

PythonアプリケーションPython(Flask/FastAPI)の場合:

# OpenTelemetry SDKをインストール
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
# auto-instrumentationでアプリを起動
SIGNOZ_ACCESS_TOKEN="" \
OTEL_EXPORTER_OTLP_ENDPOINT="http://<signoz-server>:4317" \
OTEL_RESOURCE_ATTRIBUTES="service.name=my-api-service" \
opentelemetry-instrument python app.py

Node.js(Express)の場合:

npm install @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-trace-otlp-grpc
// tracing.js — アプリのロード前に実行
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({
    url: 'http://<signoz-server>:4317',
  }),
  instrumentations: [getNodeAutoInstrumentations()],
  serviceName: 'my-node-service',
});
sdk.start();
node -r ./tracing.js server.js

ステップ3:PrometheusのmetricsをSigNozに移行する(Prometheusは捨てなくていい)

ここが個人的に一番気に入っている部分だ——既存のPrometheusに手を加える必要がない。SigNozが既存のエンドポイントから直接scrapeしてくれる:

# otel-collector-config.yamlに追記
receivers:
  prometheus:
    config:
      scrape_configs:
        - job_name: 'my-servers'
          static_configs:
            - targets:
              - 'server1:9100'   # node_exporter
              - 'server2:9100'
              - 'server3:9100'

exporters:
  clickhousemetricswrite:
    endpoint: tcp://clickhouse:9000

service:
  pipelines:
    metrics:
      receivers: [prometheus]
      exporters: [clickhousemetricswrite]

設定変更後にcollectorを再起動する:

docker compose -f docker/clickhouse-setup/docker-compose.yaml restart otel-collector

ステップ4:SigNozにlogsを送信する

SigNozはOTLP経由でlogsを受け取る。ファイルログやDockerコンテナのログを使っている場合、最も手早い方法はOpenTelemetry Collector filelog receiverだ:

receivers:
  filelog:
    include: [/var/log/myapp/*.log]
    start_at: beginning

exporters:
  otlp:
    endpoint: <signoz-server>:4317
    tls:
      insecure: true

service:
  pipelines:
    logs:
      receivers: [filelog]
      exporters: [otlp]

実践から得たTips & Tricks

1. retentionを制限してディスクを節約する

デフォルトではSigNozはデータを15日間保持する。小規模チームなら7日で十分だ:

# ClickHouse CLIにアクセス
docker exec -it signoz-clickhouse clickhouse-client

-- tracesのTTLを7日に設定
ALTER TABLE signoz_traces.signoz_index_v2
  MODIFY TTL toDateTime(timestamp) + INTERVAL 7 DAY;

-- logsのTTLを7日に設定
ALTER TABLE signoz_logs.logs
  MODIFY TTL toDateTime(timestamp) + INTERVAL 7 DAY;

2. ClickHouseのリソース制限を設定する

RAM 4GBのサーバーではリソースに上限を設けるべきだ——そうしないと、重いクエリ実行時にClickHouseが2〜2.5GBを占有し、残りのシステムリソースを圧迫する:

# docker-compose.yaml
clickhouse:
  deploy:
    resources:
      limits:
        memory: 2G
      reservations:
        memory: 1G

3. エラーレートが上昇したときにアラートを飛ばす

SigNozにはアラート機能が組み込まれており、追加インストール不要だ。APIエラーレートが5%を超えたときのアラートを作成する:

  • AlertsNew Alertに移動
  • メトリクスを選択:signoz_calls_total、フィルター:status_code = ERROR
  • 条件:5分間でrate > 0.05
  • 通知先:TelegramのwebhookまたはSlack

4. サンプルレート:デバッグ時は100%、本番は10%

開発環境でリクエスト全件をtraceするのは問題ない。本番環境では10〜20%に下げるべきだ——負荷が減り、ディスク消費も抑えられる:

# 開発環境:100%をtrace
OTEL_TRACES_SAMPLER=always_on opentelemetry-instrument python app.py

# 本番環境:10%をtrace
OTEL_TRACES_SAMPLER=parentbased_traceidratio \
OTEL_TRACES_SAMPLER_ARG=0.1 \
opentelemetry-instrument python app.py

セットアップ後の結果

デバッグのワークフローが大きく変わった。3つのタブを開く代わりに、今は:

  1. Servicesを開いて、どのサービスのp99レイテンシが高いかを確認する
  2. サービスをクリック → Traces → ステータスERRORでフィルタリング
  3. 特定のtraceをクリック → リクエストがどのステップを通過したか、どこが遅いかがすぐわかる
  4. trace表示内のLogsタブをクリック → 該当するtrace IDに対応するlogが即座に表示される

問題を発見してから原因を特定するまで:以前の30〜40分から約5分に短縮された。

コスト:$0。RAM消費:5つのサービスがtracesを送信している状態でSigNozスタック全体で約3GB。Prometheus + Grafanaを使っていて、traces/logsの統合に物足りなさを感じているなら——SigNozは自然な次のステップだ。作り直す必要はなく、本物のobservabilityレイヤーを追加するだけでいい。

Share: