概要 #
Prometheus と Grafana は監視でよく使われるが、名前だけ知っていると役割が重なって見える。どちらもグラフを表示できるし、Exporter が何のために要るのかもはっきりしない。
この2つは役割が違う。Prometheus はメトリクスを集めて保存し、問い合わせに応える。Prometheus 自身にも Graph タブがあるため、グラフ表示そのものは Grafana が無くてもできる。
Grafana が違うのは、複数の Panel をまとめた Dashboard として保存し、共有できる点である。Grafana が Prometheus に PromQL を送って結果を描くという順番を、触って確認する。
対象読者は、Prometheus の画面を開いたことがなく、PromQL もこれから学びたい人。minikube と kubectl の基本操作(kubectl apply や kubectl get)は前提とする。
この記事では PromQL の詳細、Alertmanager、Prometheus Operator、GKE への展開は扱わない。kube-prometheus-stack も使わない。
Deployment や DaemonSet の Manifest は自分で書く。Operator が後から何を隠すのかを、次回以降で比較できるようにするためである。
検証すること #
- Prometheus・Grafana・Exporter・PromQL の役割分担
- minikube 上に Prometheus・Node Exporter・Grafana を Manifest だけで構築する
- Prometheus が Node Exporter を
static_configsで scrape する経路 - Grafana に Prometheus を Data source として登録し、Dashboard を作る
- 今回の構成が非永続であること、Node Exporter が何を監視しているかの実際の範囲
今回の構成 #
Node Exporter がホストのメトリクスを /metrics に公開し、Prometheus がそれを scrape して保存する。Grafana は Prometheus に対して PromQL で問い合わせ、結果を Dashboard に描く。
図の矢印は、どちらが要求を出すかで揃えている。Node Exporter の /metrics は Prometheus から取りに行き、Grafana の Dashboard は Grafana から Prometheus へ問い合わせに行く。メトリクスと問い合わせ結果はそれぞれ逆方向に返る。
flowchart LR
subgraph minikube["minikube node"]
NE["Node Exporter
:9100/metrics"]
Prom["Prometheus
:9090"]
Graf["Grafana
:3000"]
end
Prom -- "scrape request" --> NE
Graf -- "PromQL query" --> Prom
Graf --> Dash["Dashboard"]
矢印の向きに注意する。Prometheus が Grafana へ何かを送るのではない。Grafana が Prometheus へ問い合わせに行く。
Docker Compose ではなく minikube を使うのは、この構成をそのまま Kubernetes 上に置くためである。次回以降は Kubernetes Service Discovery や Prometheus Operator へ発展させる。そのとき、今回の static_configs ベースの構成と比較できる。
前提環境 #
検証した環境と各コンポーネントの版は次のとおり。
- OS: Ubuntu 22.04.5 LTS(WSL2、カーネル
6.6.114.1-microsoft-standard-WSL2) - minikube: v1.39.0(
--driver=docker、container runtime はcontainerd) - Kubernetes: v1.37.0(single-node)
- kubectl(クライアント): v1.34.5
- Prometheus:
prom/prometheus:v3.14.0 - Node Exporter:
prom/node-exporter:v1.12.1 - Grafana:
grafana/grafana:13.2.2
kubectl クライアントとサーバーの版は3マイナーバージョン離れている。
kubectl version
Client Version: v1.34.5-dispatcher
Kustomize Version: v5.7.1
Server Version: v1.37.0
Warning: version difference between client (1.34) and server (1.37) exceeds the supported minor version skew of +/-1
Kubernetes の Version Skew Policyによると、kubectl がサポートされるのは kube-apiserver の±1マイナーバージョンのみである。今回の1.34と1.37の差はサポート範囲外で、警告どおり非推奨の組み合わせである。今回の操作(apply / get / port-forward)では実害はなかったが、入門の再現手順としてはこの版差を標準にしない。 読者は次のいずれかで、サポート範囲内の kubectl を使う。
# minikubeが同梱する、クラスタの版に合わせたkubectlを使う
minikube kubectl -- get nodes
# または、手元のkubectlをクラスタの版に合わせて入れ直す
minikubeをsingle-nodeで起動する #
第1回は構成を単純にするため、single-node の cluster に固定する。
minikube start -p prometheus-grafana-intro --driver=docker --container-runtime=containerd --nodes=1
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
prometheus-grafana-intro Ready control-plane 28s v1.37.0 192.168.157.2 <none> Debian GNU/Linux 12 (bookworm) 6.6.114.1-microsoft-standard-WSL2 (amd64) containerd://2.3.4
今回の single-node 構成では、NAME はノード名であり、-p で指定した minikube のプロファイル名と一致する。-p を省略した場合は minikube という名前になる。ノードを複数にする場合は、2台目以降のノード名にはこのルールが当てはまらない。以降のコマンドは、このプロファイルの kubectl コンテキストが選択されている前提で進める。
STATUS が Ready になるまでは数十秒かかる。NotReady のままなら、次のコマンドで CNI やコンポーネントの初期化状況を確認する。
kubectl get pods -n kube-system
kubectl describe node <ノード名>
Prometheus・Node Exporter・Grafanaをデプロイする #
Helm chart は使わず、構成が1ファイルずつ追える Manifest を使う。ディレクトリ構成は次のとおり。
sample/
├── namespace.yaml
├── prometheus/
│ ├── configmap.yaml
│ ├── deployment.yaml
│ └── service.yaml
├── node-exporter/
│ ├── daemonset.yaml
│ └── service.yaml
├── grafana/
│ ├── deployment.yaml
│ └── service.yaml
└── dashboards/
└── minikube-node-overview.json
node-exporter/daemonset.yaml は hostNetwork: true / hostPID: true / ルートの hostPath を使う。 今回は Node Exporter 公式のコンテナ実行例(--net=host / --pid=host / ルートの bind mount)に沿ってこれらを使用している。いずれも Kubernetes の Pod Security Standards では制限対象で、hostPath volume は Baseline 以上のポリシーで禁止されている。権限の強い構成であり、ローカルの学習用途以外にそのまま適用しない。
Namespace を作り、コンポーネントを順に適用する。すべてローカルの minikube 上で完結し、クラウドの課金は発生しない。以降の kubectl apply は sample/ ディレクトリに移動してから実行する。
cd sample/
kubectl apply -f namespace.yaml
kubectl apply -f prometheus/configmap.yaml
kubectl apply -f prometheus/deployment.yaml
kubectl apply -f prometheus/service.yaml
kubectl apply -f node-exporter/daemonset.yaml
kubectl apply -f node-exporter/service.yaml
kubectl apply -f grafana/deployment.yaml
kubectl apply -f grafana/service.yaml
Pod と Service の状態を確認する。
kubectl get pods -n monitoring -o wide
kubectl get svc -n monitoring
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
grafana-7d9d4457b8-lrjhj 1/1 Running 0 83s 10.244.0.4 prometheus-grafana-intro <none> <none>
node-exporter-59krd 1/1 Running 0 84s 192.168.157.2 prometheus-grafana-intro <none> <none>
prometheus-66b579486-w5x8g 1/1 Running 0 84s 10.244.0.3 prometheus-grafana-intro <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana ClusterIP 10.96.9.150 <none> 3000/TCP 83s
node-exporter ClusterIP 10.105.9.76 <none> 9100/TCP 83s
prometheus ClusterIP 10.110.18.197 <none> 9090/TCP 84s
3つとも READY が 1/1、STATUS が Running であれば成功している。Pending や CrashLoopBackOff のままなら、kubectl describe pod と kubectl logs で原因を確認する。
Node Exporterの/metricsを確認する #
Node Exporter が何を公開しているかを、Prometheus を介さずに直接見る。
kubectl port-forward -n monitoring svc/node-exporter 9100:9100
別のターミナルから /metrics を取得する。
curl -s http://localhost:9100/metrics | grep -A2 "^# HELP node_cpu_seconds_total"
# HELP node_cpu_seconds_total Seconds the CPUs spent in each mode.
# TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 489073.82
HELP がメトリクスの説明、TYPE が種類(counter や gauge)、node_cpu_seconds_total{cpu="0",mode="idle"} がラベル付きの metric 名、末尾の数値が value である。同じ形式で node_memory_MemAvailable_bytes(gauge)と node_filesystem_avail_bytes(gauge、mountpoint ラベル付き)も確認できる。
Node Exporterが実際に見ているもの #
ここまでの Manifest で /metrics は取得できるが、値の中身を見ると気になる点がある。node_filesystem_avail_bytes の mountpoint ラベルに、ホストのルート(/)が出てこない。
DaemonSet の hostPath volume には、あらかじめ mountPropagation: HostToContainer を指定してある。指定しない場合、コンテナ起動後にホスト側で新たに作られたマウントが伝播しないためで、Kubernetes の Volumes の仕様にある挙動である。
ただし、これを設定する前と後で /metrics の mountpoint 一覧を比較しても、今回の環境では差が出なかった。
Kubernetes の Volumes ドキュメントには、既定(None)でも、マウント元が Docker daemon のルートディレクトリ(/var/lib/docker)を含む場合に cri-dockerd(Docker を使う CRI)が rslave(HostToContainer と同じ効果)を選ぶことがある、とある。今回の container runtime は containerd で cri-dockerd ではないため、この記述がそのまま当てはまるとは断定できない。
今回分かったのは、この環境ではオンオフで観測できる違いが無かったという実測だけである。ルート(/)が出てこない理由は、別にある。
Node Exporter はデフォルトで overlay 型のファイルシステムを除外する。--collector.filesystem.fs-types-exclude のデフォルト値に overlay が含まれているためで、Node Exporter の Flag 一覧から確認できる。
kubectl exec -n monitoring $(kubectl get pods -n monitoring -l app=node-exporter -o jsonpath='{.items[0].metadata.name}') -- cat /host/proc/mounts | grep " /host "
overlay /host overlay ro,relatime,lowerdir=...,upperdir=...,workdir=... 0 0
minikube を --driver=docker で起動すると、Kubernetes の「ノード」は実体として1つの Docker コンテナである。そのコンテナ自身のルートファイルシステムは overlay であり、Node Exporter の既定設定では除外対象になる。
一方で、/var や /etc/hostname のようにコンテナへ個別に bind mount されているパスは ext4 としてそのまま見える。実行環境では、これらは WSL2 上の実ディスク(/dev/sdd)を指す。同じタイミングで /metrics と df -h を確認すると値が一致する。
curl -s http://localhost:9100/metrics | grep 'mountpoint="/var"' | grep -E "_size_bytes|_avail_bytes"
df -h /var/lib/docker
node_filesystem_size_bytes{device="/dev/sdd",device_error="",fstype="ext4",mountpoint="/var"} 1.081101176832e+12
node_filesystem_avail_bytes{device="/dev/sdd",device_error="",fstype="ext4",mountpoint="/var"} 8.4537745408e+11
Filesystem Size Used Avail Use% Mounted on
/dev/sdd 1007G 169G 788G 18% /var/lib/docker
1.081101176832e+12 バイトは約1007GiB、8.4537745408e+11 バイトは約788GiB で、df -h の Size と Avail にそれぞれ一致する。ディスクはマウント構成そのままの値になる。
CPU とメモリは、この構成では別の挙動になる。この minikube プロファイルには docker inspect で確認できるメモリ上限(cgroup)が設定されている。
docker inspect prometheus-grafana-intro --format 'Memory={{.HostConfig.Memory}}'
curl -s http://localhost:9100/metrics | grep "^node_memory_MemTotal_bytes"
Memory=12582912000
node_memory_MemTotal_bytes 5.051414528e+10
コンテナの cgroup メモリ上限は約12.6GB(12582912000 バイト)だが、Node Exporter が報告する MemTotal は約50.5GB(5.051414528e+10 バイト)で上限を超えている。
CPU も同様に確認する。minikube profile list -o json の設定では、このプロファイルに CPUs: 2 を記録しているが、実際の Docker コンテナに CPU 制限が入っているかは別に確認する。Docker には NanoCpus / CpusetCpus によるコア指定のほかに、CpuQuota / CpuPeriod による帯域制限もあるため、両方を確認する。
docker inspect prometheus-grafana-intro --format 'NanoCpus={{.HostConfig.NanoCpus}} CpuQuota={{.HostConfig.CpuQuota}} CpuPeriod={{.HostConfig.CpuPeriod}} CpusetCpus={{.HostConfig.CpusetCpus}}'
docker exec prometheus-grafana-intro cat /sys/fs/cgroup/cpu.max
nproc
curl -s http://localhost:9100/metrics | grep '^node_cpu_seconds_total{cpu=' | sed -n 's/.*cpu="\([^"]*\)".*/\1/p' | sort -u | wc -l
NanoCpus=0 CpuQuota=0 CpuPeriod=0 CpusetCpus=
max 100000
16
16
NanoCpus / CpuQuota / CpuPeriod はいずれも未設定(0)で、CpusetCpus も空である。cgroup v2 の cpu.max を直接見ても max 100000 で、帯域制限は掛かっていない(max が無制限を表す)。ホスト(WSL2)の nproc も Node Exporter が報告する CPU 数も、どちらも16である。minikube の設定にある CPUs: 2 は Docker driver 上では実際の cgroup 制限になっておらず、Node Exporter はホストの CPU をすべて見えている。
メモリと CPU は、cgroup が反映されない理由が異なる。 メモリはコンテナに約12.6GB の cgroup 上限が設定されているにもかかわらず、Node Exporter の MemTotal はその上限を超えて WSL2 ホスト側の値(約50.5GB)を示す。CPU はそもそもコンテナに制限自体が設定されておらず、Node Exporter から見える CPU 数も WSL2 ホストの nproc と同じ16である。ディスクは bind mount されたパスだけが個別に見え、ルートは overlay として除外される。同じ「minikube のノード」でも、メトリクスの種類によって見えている範囲が異なる。
ここでの「ホスト全体」は、この実行環境では WSL2 の Linux VM を指す。Windows 全体や物理PCの割り当て(.wslconfig 等)まで一致するかは確認していないため、そこまで一般化しない。
Prometheusのscrape設定とTargetsを確認する #
Prometheus は Kubernetes Service Discovery を使わず、static_configs で Node Exporter を直接指定している。
scrape_configs:
- job_name: node-exporter
static_configs:
- targets:
- node-exporter:9100
node-exporter:9100 は Kubernetes の Service 名とポートである。名前解決の経路は次のとおり。
flowchart LR
Config["prometheus.yml
static_configs"] --> DNS["Kubernetes Service DNS
node-exporter"]
DNS --> SVC["Service ClusterIP
:9100"]
SVC --> Pod["Node Exporter Pod
:9100"]
DNS が返すのは Node Exporter Pod の IP ではなく、node-exporter Service の ClusterIP である。今回の Service は通常の(headless ではない)Service なので、この ClusterIP から Pod へ転送される。
Prometheus の Targets を確認する。ブラウザから見る場合は kubectl port-forward -n monitoring svc/prometheus 9090:9090 のあと http://localhost:9090/targets を開く。同じ情報は API からも取得できる。
curl -s http://localhost:9090/api/v1/targets
{"scrapePool":"node-exporter","scrapeUrl":"http://node-exporter:9100/metrics","health":"up","lastScrape":"2026-09-25T04:59:50Z"}
health が up であれば、Prometheus が Service DNS 経由で Node Exporter へ到達できている。down の場合は lastError に理由が入る。
PromQLを少しだけ使う #
PromQL の詳細は次回に回すが、Grafana へ渡せる程度の最小限を確認する。
metric をそのまま取得すると、その時点の値が返る(instant vector)。
curl -s --data-urlencode 'query=node_memory_MemAvailable_bytes' http://localhost:9090/api/v1/query
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"instance":"node-exporter:9100","job":"node-exporter"},"value":[1790312030.714,"46360240128"]}]}}
rate() は counter 型の増加率を、sum() / avg() / by() はラベルをまとめて集計する。CPU 使用率は次のように書ける。
curl -s --data-urlencode 'query=100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)' http://localhost:9090/api/v1/query
{"status":"success","data":{"resultType":"vector","result":[{"metric":{},"value":[1790312202.932,"15.320895941178534"]}]}}
rate(...[5m]) が「直近5分の増加率」、avg(...) が CPU コアをまとめた平均、100 - (... * 100) が「idle 以外の割合」への変換である。メモリとディスクの使用率も同じ形で書ける。
メモリ使用率: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
ディスク使用率(/var): (1 - (node_filesystem_avail_bytes{mountpoint="/var"} / node_filesystem_size_bytes{mountpoint="/var"})) * 100
GrafanaのUIを開き、初期ログインを行う #
Grafana の UI はローカル端末から kubectl port-forward で開く。
kubectl port-forward -n monitoring svc/grafana 3000:3000
ブラウザから http://localhost:3000 を開く。Grafana 13.2.2 の初期ログインは admin / admin である。Grafana の設定リファレンスに、admin_password の既定値が admin であり、初回起動時に一度だけ設定される、とある。
curl -s -c cookies.txt -X POST http://localhost:3000/login \
-H "Content-Type: application/json" \
-d '{"user":"admin","password":"admin"}'
{"message":"Logged in","redirectUrl":"/"}
ログイン後、初回パスワード変更を行う。
curl -s -b cookies.txt -X PUT http://localhost:3000/api/user/password \
-H "Content-Type: application/json" \
-d '{"oldPassword":"admin","newPassword":"<新しいパスワード>"}'
変更後、元の cookie を使わずに admin / admin と新しいパスワードのそれぞれで再ログインし、結果が変わることを確認した。
admin/admin(変更後): {"statusCode":401,"messageId":"password-auth.failed","message":"Invalid username or password"}
新しいパスワード: {"message":"Logged in","redirectUrl":"/"}
学習用のローカル環境であっても、admin / admin のままで使い続けない。
GrafanaにPrometheusをData sourceとして登録する #
Connections > Data sources > Add data source から Prometheus を選ぶ。ここで指定する URL は、ブラウザから見た localhost:9090 ではない。
URL: http://prometheus:9090
localhost:9090 は、ローカル端末から Prometheus の UI へ入るための port-forward の宛先である。Grafana のコンテナからは別の場所になる。Grafana は同じ Namespace 内の Service 名 prometheus をクラスタ内部の DNS で解決し、Service 経由で Prometheus へ到達する。ローカル端末からの port-forward と、Grafana からのクラスタ内部通信は別の経路である。
登録後、Data source の接続確認(Save & test)を行う。
Successfully queried the Prometheus API.
Grafana Exploreを使う #
Explore で Data source に Prometheus を選び、node_memory_MemAvailable_bytes を実行する。Grafana の Prometheus data sourceは、Explore の query editor から同じ PromQL を Prometheus へ発行する。Prometheus 自身の /api/v1/query を直接呼んだ場合と同じ値が返るはずである。
Grafana バックエンド経由で Prometheus へ問い合わせる経路も、API で確認した。Data source の uid は登録時に生成され、環境ごとに異なるため、まず自分の環境の値を確認する。ログインは、初期ログインの節で変更したパスワードを使う(変更していない場合は admin)。
curl -s -c cookies.txt -X POST http://localhost:3000/login \
-H "Content-Type: application/json" \
-d '{"user":"admin","password":"<ログインに使っているパスワード>"}' >/dev/null
# 自分の環境のData source uidを確認する
curl -s -b cookies.txt http://localhost:3000/api/datasources
# 確認した uid を使って、Prometheus直接とGrafana経由をほぼ同時刻に呼ぶ
curl -s --data-urlencode 'query=node_memory_MemAvailable_bytes' http://localhost:9090/api/v1/query
curl -s -b cookies.txt "http://localhost:3000/api/datasources/proxy/uid/<確認したuid>/api/v1/query?query=node_memory_MemAvailable_bytes"
Prometheus 直接: value=[1790325801.635, "46208049152"]
Grafanaバックエンド経由: value=[1790325801.678, "46208049152"]
タイムスタンプは0.043秒違うが、値は一致している。Prometheus UI の Graph タブは Prometheus に直接問い合わせ、Grafana Explore は今回登録した Data source を介して同じ Prometheus に問い合わせる。どちらも同じ Prometheus のデータを見ている。
Dashboardを作る #
Dashboard > New > Add visualization から Panel を3つ作る。それぞれに PromQL、Unit(Percent (0-100))、Legend を設定する。PromQL 自体は前節の Prometheus API で動作を確認済みのものを使う。
| Panel | PromQL | 確認できた値 |
|---|---|---|
| CPU使用率 | 100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) |
15.3% |
| メモリ使用率 | (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 |
8.2% |
| ディスク使用率(/var) | (1 - (node_filesystem_avail_bytes{mountpoint="/var"} / node_filesystem_size_bytes{mountpoint="/var"})) * 100 |
21.8% |
GUI で作成したあと、Export メニューの「Export for sharing externally」から JSON を取り出す。このメニューは Grafana の Dashboard export API を呼んでおり、Data source が固定の UID ではなく ${DS_PROMETHEUS} という入力変数に置き換わった JSON を返す。インポート時に、自分の環境の Data source を選び直せる。取り出した JSON は sample/dashboards/minikube-node-overview.json に置いてあり、Panel の定義(PromQL・Unit・レイアウト)を確認できる。表示結果そのものの画面キャプチャは今回含めていない。
今回は永続化しないことを確認する #
Prometheus と Grafana の Deployment は、データ用の volume に emptyDir を使っている。PersistentVolume / PVC は使わない。Prometheus の TSDB は /prometheus に、Grafana の設定(Data source・Dashboard を含む)は /var/lib/grafana に、それぞれ emptyDir をマウントしている。emptyDir の仕様によると、emptyDir は Pod がノードから削除されると内容も削除される。コンテナだけが再起動する場合は保持される。
Prometheus Pod を削除して再作成させ、直前まで見えていたデータが失われることを確認する。削除の対象は monitoring Namespace の Prometheus Pod だけで、Node Exporter・Grafana には影響しない。Deployment が定義済みのため、Pod は自動的に再作成される(データは戻らない)。
curl -s --data-urlencode 'query=node_memory_MemAvailable_bytes[10m]' http://localhost:9090/api/v1/query
# 影響は monitoring Namespace の Prometheus Pod のみ。Deployment により自動で復旧する
kubectl delete pod -n monitoring -l app=prometheus
kubectl wait --for=condition=Ready pod -l app=prometheus -n monitoring --timeout=60s
# Pod が変わるとport-forwardの接続先も切れるため、張り直す
kubectl port-forward -n monitoring svc/prometheus 9090:9090 &
curl -s --data-urlencode 'query=node_memory_MemAvailable_bytes[10m]' http://localhost:9090/api/v1/query
curl -s http://localhost:9090/api/v1/targets
削除前は直近10分間に28件のサンプルが返っていたが、Pod 再作成後の同じクエリでは0件になった。Node Exporter の Target は再作成後すぐに up へ戻り、scrape 自体は継続している。
delete前: series: 1 points: 28
delete後: series: 0 points: 0
delete後のTarget: scrapeUrl=http://node-exporter:9100/metrics health=up
ここで確認したのは Prometheus の TSDB についてだけである。Grafana が GUI で作った Data source・Dashboard の設定も同じ emptyDir の仕組みで保存されているため、Grafana Pod を削除・再作成すれば同様に失われると考えられるが、Grafana 側は実際には試していない。
これは学習用の最小構成であり、そのまま本番へ持っていく構成ではない。永続化・バックアップ・HA は今回の範囲外とする。
Dashboard の JSON だけは Git 管理しているため、Grafana を作り直したあとも同じ Panel を再現できる。確認したのは Pod の削除・再作成であり、minikube stop / minikube start によるクラスタの停止・再開までは試していない。
クリーンアップする #
記事で作成した Namespace を削除すると、中の Deployment・DaemonSet・Service・Pod がまとめて消える。影響範囲は monitoring Namespace の中だけで、他の Namespace や minikube クラスタ自体には及ばない。再度必要になった場合は、sample/ の Manifest を適用し直せば同じ構成を再現できる(データは戻らない)。
kubectl delete は、そのときの kubectl コンテキストに対して実行される。複数の cluster を並行して操作していると、意図しない cluster の monitoring Namespace を消しかねない。削除の前に、対象が今回のプロファイルであることを確認する。
kubectl config current-context
prometheus-grafana-intro
コンテキストが今回のプロファイル名と一致していることを確認してから削除する。
# 影響は monitoring Namespaceの中だけ。他のNamespace・クラスタには及ばない
kubectl delete namespace monitoring
minikube 自体を止める・削除する場合は、Namespace の削除とは別の操作になる。ここでも -p でプロファイルを明示し、他のプロファイルを誤って操作しないようにする。
minikube stop -p prometheus-grafana-intro
minikube delete -p prometheus-grafana-intro
stop はクラスタの状態を残したまま停止し、次回 minikube start -p prometheus-grafana-intro で復帰できる。delete は VM/コンテナを含めて削除し、Namespace ごと消える。次回以降も検証を続ける場合は stop、完全に片付ける場合は delete を選ぶ。
まとめ #
- Prometheus はメトリクスの収集・保存・問い合わせを行い、Grafana はその結果を Dashboard として可視化・共有する。問い合わせの向きは Grafana → Prometheus である
- minikube 上に Manifest だけで Prometheus・Node Exporter・Grafana を構築し、
static_configsによる scrape 経路を確認した - Node Exporter が見ている範囲はメトリクスの種類で異なる。メモリはコンテナの cgroup 上限(約12.6GB)を超える WSL2 ホスト側の値を示し、CPU はそもそも cgroup 制限自体が設定されておらず16 CPU が見えている。ディスクは bind mount されたパスだけが個別に見える
- Grafana から Prometheus への接続は Kubernetes Service(ClusterIP)経由であり、ローカル端末からの
port-forwardとは別の経路である - 今回の構成は emptyDir のみで PVC を使わず、Prometheus Pod を再作成すると TSDB のデータが失われることを実際に確認した
- 検証で使った kubectl とクラスタの版はサポート範囲外の組み合わせであり、
node-exporterの DaemonSet は hostNetwork・hostPID・hostPath を使う権限の強い構成である。いずれも学習用のローカル環境に限定した使い方であることを明記した
参考資料 #
- minikube start
- kubectl port-forward
- Kubernetes Version Skew Policy(kubectl)
- Kubernetes Volumes(mountPropagation・emptyDir・hostPath)
- Kubernetes Pod Security Standards
- Kubernetes DNS for Services and Pods
- Prometheus Getting started(Graph タブ)
- Prometheus Configuration
- Prometheus Querying basics
- Prometheus Query functions
- Node Exporter README(Docker での実行、Flag 一覧)
- Grafana Configure Grafana(admin_password)
- Grafana Prometheus data source
- Grafana Explore
次回 #
次回はPromQLのチートシート編として、rate() / increase() / topk() / histogram_quantile() などをCPU・メモリ・ディスク・ネットワークの実用例とともに整理する。