Prometheus ExporterとGrafanaでElasticsearchおよびOpenSearchクラスターを監視する:インデックスの健全性、クエリレイテンシー、システムリソースのトラッキング

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

約5000万ドキュメントを抱えるElasticsearchクラスターをプロダクションで6ヶ月運用して、ひとつ高い授業料を払って学んだことがある:CPUとRAMの監視だけでは不十分だということだ。Grafanaでクラスターが”グリーン”になっていても、クエリレイテンシーは静かに増加していることがある。さらに悪いのは、JVMヒープが90%まで上昇しても誰も気づかず、ノードがOOM killされて初めて発覚するケースだ。

自分のPrometheus + Grafanaは現在15台のサーバーを監視しており、このセットアップのおかげでユーザーから苦情が来る前に多くの問題を検知できている。しかし、スタックにElasticsearchを追加した際は、試行錯誤に2週間近くかかった。この記事は、最初から読んでおきたかった内容だ。

ElasticsearchにはなぜElasticsearch固有の監視が必要か

CPU、RAM、ディスクI/Oといったシステムメトリクスはあくまでも表層に過ぎない。本当に複雑な問題はクラスターの内部にある:

  • Shard allocation:クラスターは動作しているが未割り当てシャードが存在する場合、データが危険な状態にある
  • クエリレイテンシー:検索p99が50msから2sに上昇していたら、インデックスの即時最適化が必要なサインだ
  • JVM GCプレッシャー:GCポーズが1秒を超えると、その間すべてのリクエストがフリーズする
  • バルクキューの拒否:インデックスキューが満杯になると、明確なエラーログなしにリクエストが拒否される
  • ディスクウォーターマーク:ディスク空き容量が < 5% になるとElasticsearchは自動的に書き込みをブロックする。早期発見しなければデータ損失につながる

アプリケーションレベルの監視がなければ、障害のデバッグは暗闇の中を手探りするようなものだ。

3つの一般的なアプローチの比較

1. X-Pack Stack Monitoring(ネイティブ)

ElasticsearchはKibana Stack Monitoringを通じた監視機能を組み込みで備えている。メトリクスはクラスター自身または別の監視専用クラスターに保存される。

  • セットアップが簡単:elasticsearch.yml に数行追加するだけで完了
  • Kibanaのインターフェースが洗練されており、クラスターヘルスの概要が最初から確認できる
  • ただし:メトリクスの保存にクラスター自身のリソースを消費する。また、Elasticがライセンスを変更した後にフォークされたOpenSearchでは、同等の機能が利用できない

2. Metricbeat

Elasticのエージェントが各ノード上で動作し、メトリクスを収集してElasticsearchまたはLogstashに送信する。

  • 豊富なモジュールがあり、設定が簡単
  • Elasticスタックとの密結合 — すでにPrometheusを使用している場合は統合できない
  • 各ノードにエージェントをデプロイし保守する必要がある — 10ノード以上のクラスターでは運用コストが無視できない

3. Prometheus Exporter(elasticsearch_exporter)

ExporterはPrometheus形式でメトリクスを公開するスタンドアロンサービスとして動作し、Prometheusが定期的にスクレイピングする。

  • 既存のPrometheus + Grafanaスタックと完全に統合できる
  • 単一のExporterでクラスター全体を監視できる — ノードごとのインストールが不要
  • ElasticsearchとOpenSearchの両方をサポート
  • Grafana Labsにコミュニティダッシュボードが用意されている

メリット・デメリットの分析 — そしてPrometheus Exporterを選んだ理由

ステージング環境で3つのアプローチを2週間テストした結果は明確だった:

X-Pack Monitoringはチームがライセンス付きのElasticスタックにオールインしている場合に適している。しかし、自分のコードベースではライセンスの自由度が高いOpenSearchを使用しているため、このオプションは早々に除外された。

Metricbeatはすでにログ転送にBeatsを使用している場合には合理的だ。しかし、新しいノードごとにエージェントのデプロイパイプラインを追加するオーバーヘッドは、小規模チームにとって避けたい負担だった。

Prometheus Exporterが選ばれたのはシンプルな理由からだ:Prometheus + Grafanaがすでに15台のサーバーで稼働しており、Exporterを1つ追加するだけで済む。既存のアーキテクチャに手を加える必要がない。OpenSearchに対しても同様に動作する — URIを変更するだけで使える。

ステップバイステップの導入手順

ステップ1:elasticsearch_exporterのインストール

prometheus-community/elasticsearch_exporter プロジェクトはDockerとバイナリの両方をサポートしている。最も手軽な方法:

docker run -d \
  --name elasticsearch-exporter \
  -p 9114:9114 \
  --restart unless-stopped \
  quay.io/prometheuscommunity/elasticsearch-exporter:latest \
  --es.uri=http://elasticsearch:9200 \
  --es.all \
  --es.indices \
  --es.shards

クラスターに認証がある場合(OpenSearch SecurityプラグインまたはElasticsearch xACL):

docker run -d \
  --name elasticsearch-exporter \
  -p 9114:9114 \
  --restart unless-stopped \
  -e ES_USERNAME=monitoring_user \
  -e ES_PASSWORD=your_password \
  quay.io/prometheuscommunity/elasticsearch-exporter:latest \
  --es.uri=https://elasticsearch:9200 \
  --es.all \
  --es.indices \
  --es.clusterinfo.interval=5m

Exporterが起動しメトリクスを公開していることを確認:

curl http://localhost:9114/metrics | grep elasticsearch_cluster_health

elasticsearch_cluster_health_status{color="green"} 1 のような出力が表示されれば、ExporterがクラスターへのOK接続に成功している。

ステップ2:Prometheusスクレイプジョブの設定

prometheus.yml にジョブを追加:

scrape_configs:
  - job_name: 'elasticsearch'
    scrape_interval: 30s
    scrape_timeout: 25s
    static_configs:
      - targets:
          - 'elasticsearch-exporter:9114'
        labels:
          cluster: 'prod-es-cluster'
          env: 'production'

再起動せずにPrometheusをリロード:

curl -X POST http://localhost:9090/-/reload

Prometheus UIにアクセスし、elasticsearch_cluster_health_status をクエリしてデータが正常に収集されていることを確認する。

ステップ3:GrafanaダッシュボードのインポートOK

Grafana LabsのダッシュボードID 14191 は、elasticsearch_exporterに対してコミュニティで最もよく使われているものだ:

  1. Grafana → Dashboards → Import
  2. ID 14191 を入力 → Load
  3. Prometheusデータソースを選択 → Import

ダッシュボードには最初から含まれている:クラスターヘルスステータス、ノード数、JVMヒープ使用率、インデックスレート、検索レート、GCコレクション時間、ノードごとのディスク使用量。

ステップ4:重要メトリクスのアラート設定

以下は自分がプロダクションで直接使用しているアラートルールセットだ。Prometheusルールファイルに追加する:

groups:
  - name: elasticsearch_alerts
    rules:
      # クラスターステータスが green ではない
      - alert: ElasticsearchClusterRed
        expr: elasticsearch_cluster_health_status{color="red"} == 1
        for: 1m
        labels:
          severity: critical

      - alert: ElasticsearchClusterYellow
        expr: elasticsearch_cluster_health_status{color="yellow"} == 1
        for: 5m
        labels:
          severity: warning

      # 未割り当てシャード
      - alert: ElasticsearchUnassignedShards
        expr: elasticsearch_cluster_health_unassigned_shards > 0
        for: 5m
        labels:
          severity: warning

      # JVM Heap > 85%
      - alert: ElasticsearchHighJVMHeap
        expr: |
          elasticsearch_jvm_memory_used_bytes{area="heap"} /
          elasticsearch_jvm_memory_max_bytes{area="heap"} > 0.85
        for: 3m
        labels:
          severity: critical

      # ディスク残量が少ない(空き容量 < 20%)
      - alert: ElasticsearchLowDiskSpace
        expr: |
          elasticsearch_filesystem_data_available_bytes /
          elasticsearch_filesystem_data_size_bytes < 0.20
        for: 5m
        labels:
          severity: warning

ステップ5:最小権限の監視用ユーザー作成

ExporterにOK管理者アカウントを使用しない — 専用ユーザーを作成する:

# Elasticsearch - APIでロールとユーザーを作成
curl -X PUT "http://localhost:9200/_security/role/monitoring_role" \
  -H 'Content-Type: application/json' \
  -u elastic:password \
  -d '{
    "cluster": ["monitor"],
    "indices": [{"names": ["*"], "privileges": ["monitor", "view_index_metadata"]}]
  }'

curl -X PUT "http://localhost:9200/_security/user/monitoring_user" \
  -H 'Content-Type: application/json' \
  -u elastic:password \
  -d '{"password": "strong_password", "roles": ["monitoring_role"]}'

OpenSearchの場合は、OpenSearch Security REST APIまたはダッシュボードUIで同様の手順で行う。

6ヶ月のプロダクション運用から学んだこと

scrape_interval 30s はほとんどのユースケースで十分だ。デバッグのために粒度を上げたい場合は15sに下げることもできるが、ExporterがES APIを呼び出す頻度が増え、クラスターのリソースをより多く消費する。

--es.shards フラグは大規模クラスターでタイムアウトを引き起こす可能性がある。800シャードを持つクラスターでこのフラグを初めて有効にした時、Exporterが頻繁にタイムアウトした。解決策:--es.timeout=30s を追加するか、シャードレベルの詳細監視が不要であればフラグを無効にする。

ダッシュボード14191はセキュリティ監査ログや異常検知ジョブのステータスなど、OpenSearch固有のメトリクスをカバーしていない。OpenSearchの拡張機能を使用している場合は、生のメトリクスから独自にパネルを構築する必要がある。

この方法の本当の価値を実感したのは、午前3時にAlertmanagerからTelegramにメッセージが届いた時だ:ノード2のJVMヒープが88%に達していた。日本のユーザーが朝のシフトに入るまでのちょうど30分間で、チームはノードを再起動してヒープ設定を更新することができた。あのアラートがなければ、確実にダウンタイムが発生し、朝6時の不愉快な電話を受けることになっていたはずだ。

この方法で最も気に入っているのは、新しいツールを学ぶ必要がない点だ。チームがすでにPrometheusとGrafanaを使いこなしていれば、1〜2時間でElasticsearchの完全な監視体制を構築できる — シャード割り当て、JVMヒープ、ディスクウォーターマーク、そしてアラートまで。

Share: