「Grafana のダッシュボードにグラフが出てるけど、あの数字って一体どこから来てるの?」
監視を触り始めると、この疑問にぶつかります。yabeda でメトリクスを仕込んで、Prometheus で集めて、Grafana で見る……名前は知っていても、データが裏でどう流れて、誰が誰に認証して画面に出ているのかは、意外とブラックボックスのまま。
この記事では、その「メトリクスが画面に出るまでの全行程」を、完全な初心者でも追えるように図解します。特に、
- 📦 データの流れ(アプリ → Prometheus → Grafana → ブラウザ)
- 🖥️ Grafana はどうやって Prometheus のデータを表示しているのか
- 🔐 認証・認可の流れ(誰が・どこで・何を認証しているのか)
の3点を、公式ドキュメントで裏を取りながら丁寧に解きほぐします。
この記事は Ruby(Rails)を例に yabeda を扱いますが、Prometheus → Grafana の流れは言語に依存しない共通の話です。Go でも Python でも Node でも、/metrics を出す部分が違うだけで後段は全部同じです。
🎭 まず登場人物(3人の役割)
┌──────────┬────────────────────────────────────────────┐
│ yabeda │ Rubyアプリに“計器”を後付けするgem。 │
│ (計装) │ アプリの状態を数値にして /metrics で公開する役 │
├──────────┼────────────────────────────────────────────┤
│ Prometheus│ その /metrics を定期的に“取りに行って”貯める。 │
│ (収集・保存)│ 時系列DB(TSDB)に保存し、PromQLで問い合わせに答える│
├──────────┼────────────────────────────────────────────┤
│ Grafana │ Prometheusに問い合わせて、結果をグラフに描く。 │
│ (可視化) │ 人間が見る“ダッシュボード”の担当 │
└──────────┴────────────────────────────────────────────┘
たとえ話にするとこうです。
yabeda = 工場の各機械に付ける“メーター”(温度計・回転計)
Prometheus= メーターを巡回して数値を記録する“検針員+台帳”
Grafana = 台帳のデータを折れ線グラフにして見せる“掲示板”
ポイントは、3人とも仕事がきれいに分かれていること。アプリは「数値を出すだけ」、Prometheus は「集めて貯めるだけ」、Grafana は「見せるだけ」。この疎結合が、後で出てくるデータ・認証の流れを理解するカギになります。
🗺️ 全体像:メトリクスが画面に出るまで
先に完成図を置きます。データは左から右へ流れます。
┌─ アプリ(Pod) ─────┐
│ yabeda │
│ ↓ 計装 │ ① アプリが数値を /metrics に貼り出す
│ GET /metrics │ puma_busy_threads 3
│ (テキスト) │ http_requests_total{...} 700
└─────────┬──────────┘
│ ② Prometheus が“取りに行く”(scrape, 例:15秒ごと)
▼
┌─ Prometheus ──────┐
│ TSDB(時系列DB) │ ③ ディスクに時系列で貯める
│ PromQLエンジン │ (いつ・どの数値が・いくつだったか)
└─────────▲──────────┘
│ ④ Grafana が PromQL で問い合わせ(HTTP API)
│ ⑤ Prometheus が JSON で返す
┌─────────┴──────────┐
│ Grafana(サーバ) │ ⑥ JSON をグラフ用に整形
└─────────▲──────────┘
│ ⑦ ブラウザへ
▼
┌─ あなたのブラウザ 🖥️ ┐ ⑧ 折れ線グラフが描画される \(^o^)/
└────────────────────┘
この①〜⑧を、これから1つずつ分解します。
① yabeda:アプリが数値を /metrics に出す
yabeda は公式の言葉を借りると 「Extendable solution for easy setup of monitoring in your Ruby apps」(Ruby アプリに監視を簡単に入れる拡張可能な仕組み)です。
yabeda は2種類のプラグインの組み合わせで出来ています。
┌─ collector(収集源:何を測るか)──────────────┐
│ yabeda-rails … HTTPリクエスト数・応答時間 │
│ yabeda-sidekiq … ジョブのqueue/処理/失敗 │
│ yabeda-puma … Webサーバのスレッド使用状況 │
├─ adapter(出力先:どこへ出すか)──────────────┤
│ yabeda-prometheus … Prometheus形式で /metrics に│
│ yabeda-datadog / -newrelic … 各SaaSへ │
└────────────────────────────────────────────────┘
メトリクスの「型」も yabeda の概念として用意されています。
| 型 | 意味 | 例 |
|---|---|---|
| counter | 増えるだけの累計 | API呼び出し回数 |
| gauge | 上下する瞬間値 | アクティブ接続数 |
| histogram | 値の分布 | 応答時間のばらつき |
yabeda-prometheus を入れると、/metrics というエンドポイントが生え、こんなただのテキストを返すようになります。
# HELP puma_busy_threads ビジーなスレッド数
# TYPE puma_busy_threads gauge
puma_busy_threads 3
# TYPE http_requests_total counter
http_requests_total{method="POST",status="200"} 700
/metrics の正体はただのテキストページです。ブラウザで開けば人間にも読めます。アプリは「今この瞬間の数値の一覧」を貼り出しているだけで、それを誰がどう使うかは知りません。この「出すだけ」の潔さが大事です。
② Prometheus:/metrics を“取りに行って”貯める(pull型)
ここで初心者がよく誤解するポイント。
❌ アプリが Prometheus に「数値できたよ!」と送る(push)
✅ Prometheus が各アプリに「数値ちょうだい」と取りに行く(pull)
Prometheus は pull 型。設定された宛先(ターゲット)の /metrics に、定期的に HTTP GET しに行きます。この「取りに行く1回の動作」を scrape(スクレイプ=こすり取る) と呼びます。
🤖Prometheus ──「今の数値ちょうだい」HTTP GET──▶ アプリ:9394/metrics
◀──── テキストをゴソッと持って帰る ─────
これを 例えば15秒ごとに繰り返す(scrape interval)
取ってきた数値は、時刻つきで TSDB(Time Series DataBase:時系列DB) にディスク保存されます。
時刻 取得した値
10:00:00 puma_busy_threads = 2
10:00:15 puma_busy_threads = 3
10:00:30 puma_busy_threads = 5 ⚠️
↑ こうやって“点”を貯めると、後で折れ線にできる
なぜ pull なのか:取りに行って応答が無ければ「そのターゲットは落ちている」と分かる(死活監視を兼ねる)、ターゲットが増えても Prometheus が宛先リストを持つだけでよくアプリ側は送信先を知らなくていい、といった利点があります。Prometheus は scrape できたかどうかを up という特別なメトリクス(成功=1 / 失敗=0)として自動で記録します。
ここまでで「数値が Prometheus の中に時系列で貯まっている」状態になりました。次がいよいよ本題、Grafana がこれをどう表示するかです。
③④⑤ Grafana はどうやって Prometheus のデータを表示しているのか
ここが一番のキモ。結論から言うと——
Grafana は自分でデータを持っていません。 表示のたびに Prometheus の HTTP API に PromQL を投げて、返ってきた JSON をグラフにしているだけです。
パネルは「PromQL の式」を持っている
Grafana のグラフ1枚(パネル)には、PromQL のクエリが紐づいています。例:
sum by(status) (rate(http_requests_total[5m]))
「直近5分のリクエスト増加レートを、ステータス別に合計して」という意味です。
Grafana → Prometheus:HTTP API を叩く
Grafana はこの式を、Prometheus の HTTP クエリ API に送ります。API は主に2種類(公式仕様)。
| エンドポイント | 用途 | 返る形(resultType) |
|---|---|---|
GET /api/v1/query |
ある1時点の値(瞬間値) |
vector(単一の値) |
GET /api/v1/query_range |
ある期間の時系列 |
matrix(値の配列) |
折れ線グラフを描くときは query_range が使われます。リクエストはこんなイメージ。
GET /api/v1/query_range
?query=sum by(status)(rate(http_requests_total[5m])) ← PromQLの式
&start=1718600000 ← 期間の開始
&end=1718603600 ← 期間の終了
&step=15s ← 何秒刻みで点を打つか(グラフの解像度)
step(解像度)は、Grafana がパネルの横幅と表示時間範囲から自動計算します。「1時間を幅800pxで表示するなら何秒刻みが妥当か」を Grafana が決めて API に渡す、という賢い仕組みです。
Prometheus → Grafana:JSON が返る
Prometheus は PromQL を TSDB に対して評価し、JSON で返します。query_range の戻りはこんな形(公式仕様より)。
{
"status": "success",
"data": {
"resultType": "matrix",
"result": [
{
"metric": { "status": "200" },
"values": [
[1718600000, "12.3"],
[1718600015, "13.1"],
[1718600030, "20.5"]
]
}
]
}
}
values の [時刻, 値] の配列が、そのまま折れ線の点になります。Grafana はこの JSON をパースして、metric(ラベル)を凡例に、values を線にしてレンダリングします。
返ってきた values: Grafana が描く線:
[10:00:00, 12.3] 値
[10:00:15, 13.1] ──────▶ 20┤ ╱
[10:00:30, 20.5] 13┤ ╱───
12┤──╱
└──────────▶ 時刻
つまり Grafana は「PromQL を投げて JSON を絵にする翻訳機」。データの実体は常に Prometheus 側にあります。ここが腑に落ちると、次の「データの流れ」と「認証」がスッと分かります。
📦 データの流れ:誰が Prometheus にリクエストしているのか?
「Grafana が Prometheus を叩く」と言いましたが、正確には“Grafana の何が”叩くのか。ここで access mode(アクセスモード)という重要な設定が出てきます。Grafana のデータソースには2つのモードがあります(公式 provisioning ドキュメントが proxy or direct (Server or Browser in the UI) と明記)。
モードA:Server(proxy)=デフォルト・推奨
🖥️ブラウザ ──「このパネル見せて」──▶ 🟦Grafanaサーバ(バックエンド)
│
│ ★Grafanaサーバが
▼ Prometheusへ問い合わせ
🤖Prometheus
│
▼ JSON
🖥️ブラウザ ◀────グラフ用データ──────── 🟦Grafanaサーバ
ブラウザは Prometheus を直接知りません。 ブラウザは Grafana サーバに頼み、Grafana サーバが代理(proxy)で Prometheus に問い合わせます。
- ✅ Prometheus は「Grafana サーバから到達できれば OK」。社内ネットワークやクラスタ内部に隠せる(外部公開不要)
- ✅ 認証情報(後述)を Grafana サーバ側で安全に付与できる。ブラウザに渡らない
- ✅ CORS(ブラウザの別ドメイン通信制限)の問題が起きない
モードB:Browser(direct)
🖥️ブラウザ ──★直接──▶ 🤖Prometheus
🖥️ブラウザ ◀──JSON─── 🤖Prometheus
(Grafanaサーバはダッシュボード定義を渡すだけ。問い合わせはブラウザ発)
ユーザーのブラウザから直接 Prometheus を叩きます。
- ⚠️ Prometheus の URL がブラウザから到達できる必要がある(≒ 公開が必要)
- ⚠️ CORS 設定が必要
- ⚠️ 認証情報の扱いが難しい
→ 特別な理由が無ければ Server(proxy)一択。だから多くの構成で「Prometheus は外部公開せず、Grafana サーバだけが内部で到達できる」形が成立します。
ここが認証の話に直結します:Server モードでは、Prometheus に実際にアクセスするのは Grafana サーバであって、エンドユーザーのブラウザではありません。つまり「ユーザーが Prometheus にログインする」のではなく、「ユーザーは Grafana にログインし、Grafana が代理で Prometheus に取りに行く」という二段構えになります。
🔐 認証・認可の流れ(3つのレイヤーに分けて理解する)
「認証認可」が分かりにくいのは、実は別々の3つの境界が混ざっているからです。1つずつ切り分けます。
レイヤーA レイヤーB レイヤーC
👤ユーザー ──認証──▶ 🟦Grafana ──認証──▶ 🤖Prometheus(自身の防御)
「Grafanaに入る権利」 「データソースに 「そもそも誰でも
接続する資格」 叩けてしまう問題」
レイヤーA:ユーザー → Grafana(人間のログイン&権限)
まず人間が Grafana に入る部分。Grafana は複数のログイン方式に対応します(公式)。
・組み込み認証 … Grafana内のユーザー名/パスワード
・OAuth … Google / GitHub / Okta 等の外部IDで入る
・LDAP / SAML … 企業のディレクトリ/SSOと連携
・プロキシ認証 … 前段のリバースプロキシで認証して引き渡す
・匿名アクセス … ログイン無しで閲覧だけ許可
ログイン後はロール(役割)で「できること」が変わります(=認可)。
| ロール | できること |
|---|---|
| Viewer | ダッシュボードの閲覧のみ |
| Editor | ダッシュボードの編集も可能 |
| Admin | 組織やデータソースの管理権限 |
ロールは組織(Organization)単位で割り当てられ、「このユーザーはこの組織では Viewer」のように制御します。
レイヤーB:Grafana → Prometheus(データソース接続の資格)
次に、Grafana が(Server モードならサーバが代理で)Prometheus に接続するときの認証。これはデータソース設定として保存されます(公式)。
選べる接続認証:
・認証なし … 内部ネットワークでPrometheusがノーガードならこれでOK
・Basic認証 … ユーザー名/パスワード
・Bearerトークン … HTTPヘッダにトークン
・TLSクライアント証明書 … 証明書で相互認証
・カスタムHTTPヘッダー … 任意のヘッダを付与
・Forward OAuth identity … ログイン中ユーザーのOAuthトークンを“転送”
┌──────────────────────────────────────────────┐
│ Serverモードでは、これらの認証情報はGrafanaサーバ側 │
│ に保管され、サーバがPrometheusへ送る。 │
│ → ブラウザ(ユーザー)には認証情報が一切渡らない 🔒 │
└──────────────────────────────────────────────┘
「Forward OAuth identity」だけ毛色が違う:通常はデータソースに固定の資格情報を持たせますが、これを使うと「Grafanaにログインした本人のOAuthトークンをそのままPrometheus(の前段)へ転送」できます。つまり「誰が問い合わせたか」をデータソース側まで引き継げる、よりきめ細かい認可が可能になります。
レイヤーC:Prometheus 自身の防御(実はここが盲点)
最後に、初心者がいちばん驚くポイント。
Prometheus は、素の状態では認証がありません。 URL を知って到達できれば、誰でもクエリできてしまいます。
だから現実の構成では、こう守ります。
守り方①:ネットワークで隠す(最も一般的)
Prometheusを外部公開せず、クラスタ内部からしか到達できなくする。
→ Grafanaサーバ(同じ内部network)だけが叩ける。これがServerモードと噛み合う
守り方②:前段にリバースプロキシ/認証ゲートウェイを置く
nginx等で Basic認証 / OAuth を掛けてからPrometheusに通す
守り方③:Prometheus自身の機能(比較的新しいバージョン)
web設定ファイルでBasic認証やTLSを有効化することも可能
┌────────────────────────────────────────────────────────┐
│ よくある安全な形: │
│ │
│ 👤 ──OAuth等──▶ 🟦Grafana ──内部network限定──▶ 🤖Prometheus│
│ (レイヤーA) (レイヤーC: 外から直接叩けない) │
│ └ データソース認証(レイヤーB)はnone でも可 │
│ なぜなら内部networkで既に守られてるから │
└────────────────────────────────────────────────────────┘
つまり「Prometheus のデータソース認証が none なのにセキュア」という状況は、レイヤーC(ネットワーク隔離)で守られているから成立するわけです。3レイヤーを分けて見ると、この一見不思議な構成も理解できます。
🎬 全行程まとめ(シーケンス)
ユーザーがダッシュボードを開いてからグラフが出るまでを、時系列で一気に。
文章で言い直すと:
-
裏では常に Prometheus がアプリの
/metricsを pull して TSDB に貯め続けている - ユーザーは Grafana にログイン(レイヤーA)
- パネルの PromQL を、Grafana サーバが Prometheus の HTTP API に投げる(Server モード+レイヤーB認証)
- Prometheus が PromQL を評価し JSON(matrix) で返す
- Grafana が JSON をグラフ用に整形してブラウザへ
- ブラウザが折れ線を描画
データの実体は常に Prometheus 側、ユーザーは Grafana 越しに間接的にそれを見ている——これが全体像です。
🏁 まとめ
┌────────────────────────────────────────────────────────┐
│ ◆ 役割分担 │
│ yabeda : アプリの状態を数値にして /metrics に出す │
│ Prometheus: /metricsをpull(scrape)→TSDBに保存→PromQLに応答│
│ Grafana : PromQLを投げJSONを受け取りグラフに描く(翻訳機) │
│ │
│ ◆ データの流れ │
│ アプリ→(pull)→Prometheus→(HTTP API/PromQL)→Grafana→ブラウザ│
│ Grafanaはデータを持たない。表示の都度Prometheusに問い合わせ │
│ access mode = Server(proxy)が基本:問い合わせるのはGrafanaサーバ│
│ │
│ ◆ 認証認可は3レイヤーで考える │
│ A. ユーザー→Grafana : ログイン+ロール(Viewer/Editor/Admin)│
│ B. Grafana→Prometheus : データソース認証(none/basic/token/TLS)│
│ C. Prometheus自身 : 素は無認証→ネットワーク隔離で守るのが定石│
└────────────────────────────────────────────────────────┘
「Grafana のグラフの数字はどこから来てるの?」の答えは、
アプリが出した数値を Prometheus が貯め、Grafana が表示のたびに PromQL で問い合わせて絵にしている。ユーザーは Grafana にログインし、Grafana が(多くの場合サーバ代理で)内部の Prometheus に取りに行っている。
これが腑に落ちれば、監視基盤のトラブルシュート(「グラフが出ない」のはアプリの /metrics? scrape? データソース接続? 権限?)も、どのレイヤーの問題かを切り分けられるようになります。
参考(公式)
- Prometheus HTTP API: https://prometheus.io/docs/prometheus/latest/querying/api/
- Grafana Prometheus data source: https://grafana.com/docs/grafana/latest/datasources/prometheus/configure/
- Grafana provisioning(access mode の記述): https://grafana.com/docs/grafana/latest/administration/provisioning/
- Grafana authentication: https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-authentication/
- yabeda: https://github.com/yabeda-rb/yabeda