#chiroito ’s blog

Java を中心とした趣味の技術について

OpenShiftでServiceMonitorを作ったのにPrometheusにメトリクスが出ないときの確認手順

OpenShift で監視を構築していると、ServiceMonitor を作成したはずなのに、Prometheus に対象のメトリクスがまったく出てこないことがあります。

こういうとき、最初に確認したくなるのは Service や Endpoint、あるいは /metrics の中身そのものですが、その前に見ておくと切り分けがかなり早くなるポイントがあります。
それが、Prometheus がその ServiceMonitor を認識しているかどうかです。

この記事では、Prometheus の api/v1/targets を使って、ServiceMonitor がどこまで認識されているのかを確認し、設定ミスとスクレイプ失敗を切り分けたときの流れをまとめます。

まず確認したいこと

今回のポイントは、次の 2 段階を分けて考えることです。

  1. Prometheus は ServiceMonitor を見つけられているか
  2. 見つけたあと、実際に /metrics を正常にスクレイプできているか

この 2 つは似ているようで別の問題です。
ServiceMonitor が正しく認識されていなくてもメトリクスは出ませんし、ServiceMonitor が認識されていても、スクレイプ先の形式が不正ならやはりメトリクスは出ません。

その切り分けに便利なのが api/v1/targets です。

Prometheus の api/v1/targets を確認する

Prometheus Pod の中から API を叩くと、Prometheus が見つけた監視対象を JSON で確認できます。

oc exec -c prometheus <prometheus-pod-name> -- \
  curl -s 'http://localhost:9090/api/v1/targets' | jq

この API では、Prometheus が「見つけようとしたもの」と「実際に監視対象として扱っているもの」の両方を確認できます。

見るべき項目

特に重要なのは次の項目です。

項目 意味 何がわかるか
activeTargets 現在スクレイプ対象になっているもの 正常に認識され、監視対象に入っているか
droppedTargets 発見したが除外されたもの 見つけてはいるが設定上の理由で捨てられていないか
labels 最終的に付与されるラベル jobnamespace などが意図通りか
health ターゲットの状態 up / down / unknown を確認できる
lastError 直近のエラー内容 スクレイプ失敗の理由を直接確認できる

ここで重要なのは、Prometheus に出てこない = まったく認識されていない、とは限らないという点です。 droppedTargets に入っていれば、Prometheus は発見まではできていることになります。

今回は droppedTargets に入っていた

今回、自分で登録した ServiceMonitor は activeTargets ではなく droppedTargets に入っていました。

この状態を見ると、少なくとも次のことがわかります。

  • ServiceMonitor に由来する候補は Prometheus に見つかっている
  • ただし最終的には監視対象として採用されていない
  • つまり問題は「未発見」ではなく「設定による除外」の可能性が高い

この段階で、ネットワークやアプリケーション側の /metrics を疑うより先に、ServiceMonitor の設定を見直すべきだと判断できます。

原因は ServiceMonitor のラベル不足だった

設定を見直したところ、今回は ServiceMonitor に付けるべきラベルが不足していました。

metadata:
  labels:
    k8s-app: hello-app-monitor

このラベルを付与し直すと、ServiceMonitor は正しく認識されるようになりました。

つまり、最初の問題は /metrics の中身そのものではなく、Prometheus がその ServiceMonitor を適切に拾える形になっていなかったことでした。

認識されたあとに、別の問題が見えた

ラベル修正後は activeTargets に対象が現れるようになりました。 ここで次に確認すべきなのが healthlastError です。

今回のターゲットは activeTargets に入ったものの、状態は down になっており、lastError には次のような内容が出ていました。

non-compliant scrape target sending blank Content-Type and no fallback_scrape_protocol specified for target

この状態は、ServiceMonitor の認識自体は成功している一方で、スクレイプ対象のレスポンス形式に問題があることを意味しています。

つまり、問題は次のように段階的に切り分けられました。

第1段階

ServiceMonitor が Prometheus に正しく認識されていなかった → ラベル不足が原因

第2段階

ServiceMonitor は認識されたが、スクレイプは失敗していた → /metrics の形式が Prometheus 互換ではなかった

今回のケースでは MicroProfile Metrics を読ませていた

最終的には、Prometheus が読みにいっていた /metrics が、Prometheus にとって期待どおりの形式ではありませんでした。

今回は誤って MicroProfile Metrics を読ませていたため、Prometheus 側でエラーになっていました。

この時点で見えていたのは、次のような事実です。

  • ServiceMonitor の認識は成功している
  • ターゲットも activeTargets に入っている
  • しかし healthdown
  • lastError にレスポンス形式の問題が明示されている

ここまで来ると、確認対象は Kubernetes リソースの関連付けではなく、実際に /metrics で返している内容に絞れます。

切り分けの順番として有効だったこと

今回の確認で特に有効だったのは、いきなり原因をひとつに決め打ちせず、Prometheus の見え方を順番に確認したことです。

おすすめの順番は次の通りです。

1. api/v1/targets を見る

まずは Prometheus が対象をどう見ているかを確認します。

2. activeTargets と droppedTargets を分けて考える

  • どちらにもいないなら、発見条件を疑う
  • droppedTargets にいるなら、設定による除外を疑う
  • activeTargets にいるなら、次はスクレイプ結果を見る

3. health と lastError を確認する

ここで通信失敗なのか、認証エラーなのか、フォーマット不正なのかが見えてきます。

まとめ

ServiceMonitor を作ったのに Prometheus にメトリクスが出ないときは、まず api/v1/targets を見ると状況をかなり整理できます。

今回の流れでは、問題は次の 2 つに分かれていました。

  • 最初は ServiceMonitor のラベル不足により、Prometheus に正しく採用されていなかった
  • その修正後は、今度は /metrics の形式が Prometheus に適合せずスクレイプに失敗していた

このように、ServiceMonitor が認識されているかと、認識されたうえで正常にスクレイプできているかは別問題として切り分けるのが重要です。

Prometheus 側の見え方を先に確認しておくと、Kubernetes の設定ミスなのか、メトリクスの内容の問題なのかを早い段階で判断しやすくなります。

同じように「ServiceMonitor を作ったのに何も見えない」という状況に遭遇したときは、まず api/v1/targets を確認してみるとよいと思います。