OpenShift で監視を構築していると、ServiceMonitor を作成したはずなのに、Prometheus に対象のメトリクスがまったく出てこないことがあります。
こういうとき、最初に確認したくなるのは Service や Endpoint、あるいは /metrics の中身そのものですが、その前に見ておくと切り分けがかなり早くなるポイントがあります。
それが、Prometheus がその ServiceMonitor を認識しているかどうかです。
この記事では、Prometheus の api/v1/targets を使って、ServiceMonitor がどこまで認識されているのかを確認し、設定ミスとスクレイプ失敗を切り分けたときの流れをまとめます。
まず確認したいこと
今回のポイントは、次の 2 段階を分けて考えることです。
- Prometheus は ServiceMonitor を見つけられているか
- 見つけたあと、実際に
/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 |
最終的に付与されるラベル | job や namespace などが意図通りか |
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 に対象が現れるようになりました。
ここで次に確認すべきなのが health と lastError です。
今回のターゲットは 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に入っている - しかし
healthはdown 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 を確認してみるとよいと思います。