ThanosでPrometheusを拡張する設定ガイド:長期メトリクス保存と複数クラスターのグローバルビュー

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

ThanosはPrometheusが解決できない何を解決するのか?

以前、3つの独立したKubernetesクラスターでPrometheusを運用していました。各クラスターには個別のGrafanaとアラートがありました。顧客から「先月のプロダクション環境のサービスXのメトリクスはいくつですか?」と聞かれると、3つのタブを開き、各クラスターを探してExcelに数値をコピーペーストする必要がありました。単純な質問一つに20分もかかっていました。

Prometheusはデフォルトで15日分のデータしか保持せず、すべてのクラスターを一箇所で確認する方法もありません。Thanosはまさにこの2つの悩みを解決するために生まれました。

クイックスタート:Thanosを10分で動かす

最も手軽に試す方法は、S3をシミュレートするオブジェクトストレージとしてMinIOを使ったDocker Composeです。AWSもアカウントも不要です。

ステップ1:バケット設定ファイルの作成

mkdir -p ~/thanos-demo && cd ~/thanos-demo

cat > bucket.yaml <<EOF
type: S3
config:
  bucket: thanos
  endpoint: minio:9000
  access_key: minioadmin
  secret_key: minioadmin
  insecure: true
EOF

ステップ2:スタック全体のDocker Compose

# docker-compose.yml
version: '3.8'
services:
  minio:
    image: minio/minio:latest
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - minio_data:/data

  prometheus:
    image: prom/prometheus:latest
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.max-block-duration=2h'
      - '--storage.tsdb.min-block-duration=2h'
      - '--web.enable-lifecycle'
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    ports:
      - "9090:9090"

  thanos-sidecar:
    image: thanosio/thanos:latest
    command:
      - sidecar
      - --tsdb.path=/prometheus
      - --prometheus.url=http://prometheus:9090
      - --objstore.config-file=/bucket.yaml
      - --http-address=0.0.0.0:10902
      - --grpc-address=0.0.0.0:10901
    volumes:
      - prometheus_data:/prometheus
      - ./bucket.yaml:/bucket.yaml
    depends_on:
      - prometheus
      - minio

  thanos-store:
    image: thanosio/thanos:latest
    command:
      - store
      - --objstore.config-file=/bucket.yaml
      - --http-address=0.0.0.0:10902
      - --grpc-address=0.0.0.0:10901
    volumes:
      - ./bucket.yaml:/bucket.yaml
    depends_on:
      - minio

  thanos-query:
    image: thanosio/thanos:latest
    command:
      - query
      - --http-address=0.0.0.0:9091
      - --endpoint=thanos-sidecar:10901
      - --endpoint=thanos-store:10901
    ports:
      - "9091:9091"
    depends_on:
      - thanos-sidecar
      - thanos-store

volumes:
  minio_data:
  prometheus_data:

ステップ3:最小限のprometheus.ymlの作成

# prometheus.yml
global:
  scrape_interval: 15s
  external_labels:
    cluster: 'demo'
    replica: '0'

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

ステップ4:起動とMinIOバケットの作成

# スタック全体を起動
docker compose up -d

# MinIOに'thanos'バケットを作成(mcクライアントを使用)
docker run --rm --network host \
  minio/mc alias set local http://localhost:9000 minioadmin minioadmin

docker run --rm --network host \
  minio/mc mb local/thanos

以上です。http://localhost:9091を開くとThanos Query UIが表示されます。ここでPromQLを入力すると、実行中のPrometheusとMinIOに保存された履歴データの両方から透過的にデータを取得できます。

Thanosのアーキテクチャ:各コンポーネントの役割

ThanosはPrometheusを置き換えるのではなく、その上に機能を追加します。同僚にはよくこう説明しています:Prometheusは現場の小さな倉庫、Thanosはすべてをつなぐ中央倉庫システムだと。

Sidecar — PrometheusとObject Storageをつなぐ橋

Prometheusと同じPodで動作します。役割は2つ:Thanos QueryがリアルタイムデータをプルするためのgRPCエンドポイントの公開と、2時間ごとにブロックデータをS3/MinIOにアップロードすることです。

重要な注意点:Prometheusに--storage.tsdb.max-block-duration=2hを設定する必要があります。これにより、Sidecarは書き込み中のブロックには触れず、完全にクローズされたブロックのみをアップロードします。

Store Gateway — 履歴ストレージへの入口

15日以上前のデータが必要な場合、QueryはStore Gatewayに問い合わせます。このコンポーネントはS3からブロックを取得してインデックスをメモリに読み込み、結果を返します。実際のデータはローカルに保存せず、高速検索のためにインデックスのみをキャッシュします。

Query — 単一のクエリエンドポイント

Grafanaとユーザーはすべてここにアクセスします。Thanos Queryは自動的に判断します:新しいデータはSidecarに、古いデータはStore Gatewayに問い合わせます。複数のPrometheusレプリカが同じターゲットをスクレイプしている場合、手動介入なしに自動で重複排除します。

Compactor — クリーンアップとコスト削減

定期的に独立して実行されます。小さなブロックを大きなブロックにまとめ、古いデータをダウンサンプリングします。1年前のブロックは15秒の粒度は不要で、トレンドを見るには1時間のダウンサンプリングで十分です。

複数クラスターのKubernetesへの実際のデプロイ

これが実務で最もよく使うパターンです。各クラスターが独自のPrometheus+Sidecarを実行し、すべてが同じS3バケットにデータを送信します。Thanos Queryは中央クラスターに配置し、gRPC経由ですべてのSidecarと接続します。

External labels — 必須設定

# プロダクションクラスター
global:
  external_labels:
    cluster: 'production-sg'
    region: 'ap-southeast-1'

---
# ステージングクラスター
global:
  external_labels:
    cluster: 'staging-sg'
    region: 'ap-southeast-1'

external_labelsの設定漏れはThanos初心者が最もよく犯すミスです。識別ラベルなしに2つのクラスターのデータが同じS3バケットに流れ込むと、Queryは重複排除の方法が分からず、クエリ結果が二重になり、アラートが誤って発火します。このステップは絶対に省略しないでください。

複数クラスターを一つのThanos Queryに接続

# 複数クラスターのSidecarに接続するThanos Query
thanos query \
  --http-address=0.0.0.0:9091 \
  --endpoint=prod-sidecar.monitoring.svc:10901 \
  --endpoint=staging-sidecar.monitoring.svc:10901 \
  --endpoint=thanos-store.monitoring.svc:10901 \
  --query.replica-label=replica

このセットアップを導入する前は、確認のためにサーバーごとにSSHで接続していました。今はThanos QueryをデータソースとするGrafanaのダッシュボードで、clusterラベルでフィルタリングするだけで、プロダクションとステージングの両方を同一グラフで確認できます。

AWS S3への実際の長期ストレージ設定

# 本番環境用 bucket-s3.yaml
type: S3
config:
  bucket: company-thanos-metrics
  endpoint: s3.ap-southeast-1.amazonaws.com
  region: ap-southeast-1
  # EC2/EKS上で実行する場合はキーをハードコードせずIAM Roleを使用
  access_key: ${AWS_ACCESS_KEY_ID}
  secret_key: ${AWS_SECRET_ACCESS_KEY}

ストレージコスト削減のためのCompactor追加

thanos compact \
  --data-dir=/tmp/thanos-compact \
  --objstore.config-file=/bucket-s3.yaml \
  --retention.resolution-raw=30d \
  --retention.resolution-5m=90d \
  --retention.resolution-1h=1y \
  --wait

この設定では生データを30日、5分ダウンサンプリングを90日、1時間ダウンサンプリングを1年保持します。約50万のアクティブシリーズを持つシステムで実測したところ、Compactorとダウンサンプリングを有効化した後、1年間15秒の解像度で保持し続けた場合と比較してS3のコストが約65%削減されました。

運用経験から得た実践的なTips

1. PrometheusでThanos自体を監視する

Thanosはポート10902に/metricsを公開しています。スクレイプ設定に追加することで、顧客からの報告を待つより先に、Compactorが停止したりStore Gatewayが新しいブロックを同期できなくなったりした際にすぐ気づけます。

scrape_configs:
  - job_name: 'thanos-components'
    static_configs:
      - targets:
          - 'thanos-query:10902'
          - 'thanos-store:10902'
          - 'thanos-sidecar:10902'

2. Thanos導入後はPrometheusのretentionを短縮する

# Prometheusは2〜7日分のみ保持、残りはThanosが管理
prometheus \
  --storage.tsdb.retention.time=7d \
  --storage.tsdb.max-block-duration=2h \
  --storage.tsdb.min-block-duration=2h

3. ブロックがS3にアップロードされたか確認する

# thanos toolsでバケットを検査
thanos tools bucket inspect \
  --objstore.config-file=bucket.yaml \
  --output=table

4. 「duplicate samples」エラーへの対処

Grafanaでデータが二重に表示される場合、Thanos Queryに重複排除フラグを追加します:

thanos query \
  --query.replica-label=replica \
  --query.auto-downsampling \
  [その他のエンドポイント]

5. SidecarがS3への接続を失った場合のアラート

# Thanos用アラートルール
groups:
  - name: thanos
    rules:
      - alert: ThanosSidecarBucketOperationsFailed
        expr: rate(thanos_objstore_bucket_operation_failures_total[5m]) > 0
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "ThanosのSidecarがObject Storageにアップロードできません"

Thanos vs Cortex vs VictoriaMetrics — どれを選ぶべきか?

この質問はよく受けます。答えはスケールとアーキテクチャ変更への許容度によって異なります。

ThanosはすでにPrometheusを使っている場合に最適です。Sidecarを追加するだけで、既存のスクレイプ設定を変更する必要はありません。VictoriaMetricsは同じハードウェアでPrometheusの5〜10倍のスループットを処理でき、RAMの消費も少ないですが、完全な移行が必要です。Cortexは大規模環境(毎秒数億サンプル)では強力ですが、メタデータストアとしてCassandraまたはDynamoDBが必要で、運用オーバーヘッドが無視できません。

10クラスター未満、アクティブシリーズ100万未満であれば、Thanosが最も現実的な選択肢です。過度なエンジニアリングは不要です。

Share: