
Prometheusとは、監視対象が公開しているHTTPのエンドポイントから数値(メトリクス)を一定間隔で取りに行き、時系列データベースに保存するオープンソースの監視システムです。一方のGrafanaは、その数値をグラフやダッシュボードとして表示する可視化ツールで、Prometheus+Grafanaの組み合わせは自宅サーバーからKubernetesまで広く使われています。
この記事では、監視用のサーバー1台にDocker ComposeでPrometheus 3.14.0とGrafana 13.2.2(いずれも執筆時点)を立て、node_exporterでOSの数値を集め、CPU・メモリ・ディスク・ネットワークのダッシュボードとディスク残量のアラートを作ります。設定はすべて実際に起動して確かめ、途中で出たエラーもそのまま載せています。
この記事でわかること
- Prometheus、Grafana、node_exporter、Alertmanagerの役割分担と使うポート
- Docker Composeで監視サーバーを立てる設定一式(データソースの自動登録つき)
- Proxmoxや他のサーバーにnode_exporterを入れて監視対象を増やす手順
- CPU・メモリ・ディスク・ネットワークを見るPromQLと、死活・ディスク残量のアラートルール
context deadline exceededや権限エラーなど、実際に出たエラーの直し方
PrometheusとGrafanaの違い:役割分担とポート
名前がよく並べて出てくるので混同されますが、PrometheusとGrafanaは別の仕事をしています。数値を集めて保存し、計算し、しきい値を判定するのがPrometheus、それを人が見る画面にするのがGrafanaです。OSの数値を公開する係としてnode_exporterが、アラートの通知を束ねる係としてAlertmanagerが加わります。
| コンポーネント | 既定のポート | 役割 | 動かす場所 |
|---|---|---|---|
| node_exporter | 9100 | CPU・メモリ・ディスク・ネットワークなどの数値を /metrics で公開する | 監視される各ホスト |
| Prometheus | 9090 | /metrics を定期的に取得(スクレイプ)して保存し、PromQLで計算し、アラートルールを評価する | 監視サーバー |
| Alertmanager | 9093 | Prometheusが出したアラートをまとめ、メールやチャットへ通知する | 監視サーバー |
| Grafana | 3000 | Prometheusなどのデータをグラフにし、ダッシュボードとして表示する | 監視サーバー |
Prometheusは、監視対象へ自分から取りに行く「プル型」です。監視対象の一覧はPrometheusの設定ファイルにあり、取りに行って失敗すると up という値が0になるため、「数値が来ない」こと自体を死活監視に使えます。監視対象側は /metrics を公開するだけで、どこに送るかを知る必要がありません。
ZabbixのようなオールインワンのツールはエージェントとWeb画面、通知までを1つの製品で持ち、テンプレートをGUIで当てていく運用に向いています。対するPrometheus側は、PromQLという問い合わせ言語で数値を自由に組み合わせられ、コンテナやKubernetesとの相性が良いのが特徴です。Docker、Proxmox、k3sで組んだホームラボならPrometheus+Grafana、ネットワーク機器をSNMPで大量に見る社内環境やWindows中心の環境ならZabbix、という分け方が実用的です。
構成:監視サーバー1台と、監視されるホスト
監視サーバーではPrometheusとGrafanaをDocker Composeで動かし、同じサーバー自身の数値はコンテナのnode_exporterで取ります。ProxmoxのホストやVMなど、ほかのサーバーにはパッケージのnode_exporterを入れて、監視サーバーから9100番を取りに行きます。
データの量は、時系列(メトリクス名とラベルの組み合わせ)の数×取得回数で決まります。検証用ホストのnode_exporterが公開していた時系列は1,280本でした(CPUのコア数、ディスクやNICの数で増減します)。保存形式は1サンプルあたり1〜2バイト程度まで圧縮されるので、例として5台・各1,300本・30秒間隔・1サンプル2バイトで計算すると、1日あたり約37MB、30日で約1.1GBです。ディスクに余裕があれば保持期間を延ばし、少なければ取得間隔を60秒にして半分にできます。保持期間の既定値は15日で、この記事では --storage.tsdb.retention.time=30d で30日にしています。
Docker Composeで監視サーバーを起動する
作業ディレクトリ ~/stacks/monitoring/ に次の構成でファイルを置きます。監視サーバーのLAN側アドレスは例として 192.168.10.5 にしています。
compose.yaml
.env # GRAFANA_ADMIN_PASSWORD=...(chmod 600)
prometheus/prometheus.yml
prometheus/rules/node.yml
grafana/provisioning/datasources/prometheus.ymlservices:
prometheus:
image: prom/prometheus:v3.14.0
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --storage.tsdb.retention.time=30d
- --web.enable-lifecycle
volumes:
- ./prometheus:/etc/prometheus:ro
- prom_data:/prometheus
ports:
- "127.0.0.1:9090:9090"
extra_hosts:
- "host.docker.internal:host-gateway"
restart: unless-stopped
node-exporter:
image: prom/node-exporter:v1.12.1
command:
- --path.rootfs=/host
network_mode: host
pid: host
volumes:
- /:/host:ro,rslave
restart: unless-stopped
grafana:
image: grafana/grafana:13.2.2
environment:
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD}
GF_USERS_ALLOW_SIGN_UP: "false"
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning:ro
ports:
- "192.168.10.5:3000:3000"
restart: unless-stopped
volumes:
prom_data:
grafana_data:設定の意図を順に説明します。node-exporterだけ network_mode: host と pid: host にし、ホストのルートを /host に読み取り専用でマウントして --path.rootfs=/host を渡しています。こうしないと、ネットワークの数値がコンテナ自身の仮想NICのものになり、ディスクもコンテナから見えるものだけになります。ブリッジネットワークにいるPrometheusからホストの9100番へは、extra_hosts で定義した host.docker.internal(Dockerのホスト側ゲートウェイ)で届きます。
9090番(Prometheus)は 127.0.0.1 だけに公開しています。--web.enable-lifecycle を付けると設定の再読み込みAPIが使えるようになる一方、同じ仕組みでPrometheusを停止させるAPI(/-/quit)も有効になり、認証はありません。LANやインターネットに9090番を公開すると、届いた人は誰でも監視を止められます。
一方で、家族や同僚も見る3000番(Grafana)はLAN側アドレスに公開し、外出先からはTailscaleで自宅サーバーにリモート接続する方法で入ります。
イメージ名は grafana/grafana を選んでいます。執筆時点では grafana/grafana-oss も配布されていますが、latest が13.0.2のまま止まっていて、grafana/grafana の13.2.2より古くなっていました。データの保存先をバインドマウントではなく名前付きボリュームにしているのは、後述する権限エラーを避けるためです。
global:
scrape_interval: 30s
evaluation_interval: 30s
rule_files:
- /etc/prometheus/rules/*.yml
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ["localhost:9090"]
- job_name: node
static_configs:
- targets: ["host.docker.internal:9100"]
labels:
host: monitor
- targets: ["192.168.10.11:9100"]
labels:
host: pve1labels で付けた host は、ダッシュボードやアラートの文面で「どのマシンか」を人間向けの名前で示すためのものです。instance ラベル(192.168.10.11:9100 のような接続先)だけでは、IPアドレスを覚えていないと読めません。
groups:
- name: node
rules:
- alert: HostDown
expr: up{job="node"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "{{ $labels.host }} から5分間メトリクスを取得できません"
- alert: DiskAlmostFull
expr: |
node_filesystem_avail_bytes{fstype!~"tmpfs|overlay|squashfs"}
/ node_filesystem_size_bytes{fstype!~"tmpfs|overlay|squashfs"} < 0.10
for: 15m
labels:
severity: warning
annotations:
summary: "{{ $labels.host }} の {{ $labels.mountpoint }} の空きが10%未満です"apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
uid: prometheus
access: proxy
url: http://prometheus:9090
isDefault: trueprovisioning/datasources/ に置いたファイルは起動時にGrafanaが読み込み、画面で操作しなくてもデータソースが登録されます。URLの prometheus はComposeのサービス名です。起動前に、Prometheusイメージに同梱の promtool で設定とルールを検査しておきます。
cd ~/stacks/monitoring
chmod 600 .env
docker compose run --rm --entrypoint promtool prometheus check config /etc/prometheus/prometheus.yml
docker compose run --rm --entrypoint promtool prometheus check rules /etc/prometheus/rules/node.yml
docker compose up -dcheck config が SUCCESS: /etc/prometheus/prometheus.yml is valid prometheus config file syntax を、check rules が SUCCESS: 2 rules found を返せば問題ありません。以後、prometheus.ymlやルールを書き換えたときは curl -X POST http://127.0.0.1:9090/-/reload で再読み込みでき、成功すると200が返ります。
監視対象を増やす:Proxmoxや他のサーバーにnode_exporterを入れる
UbuntuやDebian系のサーバー(Proxmox VEのホストを含む)には、パッケージのnode_exporterを入れるのが手軽です。systemdのサービスとして登録され、9100番で待ち受けます。Ubuntu 24.04のパッケージは1.7.0(執筆時点)とDockerイメージより古い版ですが、CPU・メモリ・ディスク・ネットワークといった基本の数値は同じ名前で取れます。
sudo apt install prometheus-node-exporter
curl -s http://127.0.0.1:9100/metrics | grep -c '^node_'
sudo ufw allow from 192.168.10.5 to any port 9100 proto tcp9100番にはカーネルの版やマウントポイント、NICの名前などが並ぶので、監視サーバー以外からは見えないようにします。上の例はufwの場合で、Proxmox VEのファイアウォールを使っている場合はデータセンターかノードのルールに同じ条件を書きます。そのうえで監視サーバーの prometheus.yml に targets を足し、reloadすれば取得が始まります。ProxmoxのホストやVMの構成はProxmox VEで自宅サーバーを構築するガイドにまとめています。
PromQLで見る:CPU・メモリ・ディスク・ネットワーク
node_exporterの数値の多くは「起動してからの累計」を表すカウンターで、そのままグラフにしても右肩上がりの線になるだけです。rate() で1秒あたりの増え方に直してから使います。範囲の [5m] は、取得間隔(ここでは30秒)の4倍以上を目安にします。範囲内に2点以上のサンプルがないと値が計算できないためです。
| 見たいもの | PromQL | 読み方 | ||||
|---|---|---|---|---|---|---|
| CPU使用率(%) | 100 * (1 - avg by (host) (rate(node_cpu_seconds_total{mode="idle"}[5m]))) | アイドル時間の割合を全コアで平均し、100から引く | ||||
| メモリ使用率(%) | 100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) | キャッシュとして解放できる分を除いた実質の使用率 | ||||
| ディスク空き率(%) | `100 * node_filesystem_avail_bytes{fstype!~"tmpfs | overlay | squashfs"} / node_filesystem_size_bytes{fstype!~"tmpfs | overlay | squashfs"}` | 一時領域とコンテナのレイヤーを除いた実ディスク |
| 受信速度(bps) | `rate(node_network_receive_bytes_total{device!~"lo | veth.* | docker.* | br-.*"}[5m]) * 8` | バイトをビットに直し、仮想NICを除く | |
| 死活 | up | 1なら取得成功、0なら失敗 |
これらはPrometheusの画面(http://127.0.0.1:9090)のQueryで試せます。検証中にこのディスク空き率のクエリを実行したところ、検証用ホストのルートが7%と表示され、df -h / で確かめると実際に使用率93%でした。後から入った別の作業のデータで埋まりかけていたもので、ダッシュボードを作った初日に役に立った例です。
メモリ使用率を node_memory_MemFree_bytes で計算すると、Linuxがページキャッシュとして使っている分まで「使用中」に数えられ、常に90%超のような値になります。MemAvailable を使うのはこのためです。ZFSを使うProxmoxやTrueNASでは、ARC(ZFSのキャッシュ)がMemAvailableに含まれず高めに見えるので、node_zfs_arc_size と並べて読みます。
アラートルール:死活とディスク残量
前の章のルールでは、HostDown が5分間 up が0のままなら、DiskAlmostFull が空き10%未満の状態が15分続いたら発火します。for: の間は「pending(保留)」、条件を満たし続けると「firing(発火)」に変わる仕組みで、一瞬の揺れで通知が飛ぶのを防ぎます。検証では、わざと存在しないアドレスを監視対象に入れておくと HostDown がpendingになり、空きの少なかった検証用ホストでは DiskAlmostFull もpendingになりました。状態はPrometheusの画面のAlertsで確認できます。
発火したアラートを実際に通知するには、Alertmanagerを追加してPrometheusの alerting: 設定でその宛先を指定し、Alertmanager側でメール、Slack、Discord、汎用のWebhookなどの送り先を決めます。まずはPrometheusの画面でpending・firingを確認できるところまで作り、通知は送り先が決まってから足す順番で問題ありません。
ダッシュボードを作る:Grafanaの初期設定とNode Exporter Full
http://192.168.10.5:3000 を開き、ユーザー名 admin と .env に書いたパスワードでログインします。表示言語には日本語が同梱されていて、プロフィールの設定で言語を日本語に切り替えられます(検証ではAPI経由で ja-JP を設定できることも確認しました)。データソースは起動時に自動登録されているので、接続の設定は不要です。
最初の1枚は、grafana.comで公開されている「Node Exporter Full」(ID 1860)を読み込むのが早道です。新規作成メニューからインポートを選び、IDに 1860 を入力して読み込み、データソースにPrometheusを選べば、CPU・メモリ・ディスク・ネットワークのパネルが並んだ画面ができます(メニュー名は執筆時点のもので変わることがあります)。画面上部の変数でjobに node を選び、ホストの選択欄で対象を切り替えれば、1つのダッシュボードで全台を見られます。
自分でパネルを作るときは、前の章のPromQLをそのまま使います。1つのパネルに1つの問いを置くのがコツで、「ディスク空き率が低い順の表」「CPU使用率の推移」のように、見た瞬間に判断できる形にします。作ったダッシュボードのJSONはエクスポートしてGitで管理しておくと、作り直しや他の環境への移植が楽になります。
つまずきポイント
監視対象がDOWNで context deadline exceeded と出る
Prometheusの画面のTargets(またはAPI)に Get "http://192.168.10.11:9100/metrics": context deadline exceeded と表示される場合は、時間内に応答が返っていません。監視サーバーから curl -s -m 5 http://192.168.10.11:9100/metrics | head -3 を実行し、同じように待たされるならファイアウォール、connection refused ならnode_exporterが動いていないか待ち受けアドレスの違いです。
Grafanaが起動しない:GF_PATHS_DATA is not writable
データ保存先をホストのディレクトリにバインドマウントすると、ログに GF_PATHS_DATA='/var/lib/grafana' is not writable. と出て起動に失敗します。コンテナが一般ユーザー(UID 472)で動くためで、名前付きボリュームに変えるか、sudo chown -R 472:0 ./grafana-data で所有者を合わせます。
Prometheusが起動しない:queries.active: permission denied
Prometheusのデータ保存先も同じで、rootが所有するディレクトリをマウントすると open /prometheus/queries.active: permission denied で止まります。こちらのコンテナは nobody(UID 65534)で動くので、名前付きボリュームにするか sudo chown -R 65534:65534 ./prom-data とします。
設定を書き換えても反映されない
prometheus.ymlを編集しただけでは反映されません。curl -X POST http://127.0.0.1:9090/-/reload を実行するか、--web.enable-lifecycle を付けていない場合は docker compose restart prometheus が必要です。書式の誤りがあると再読み込みは失敗し、古い設定のまま動き続けるので、先に promtool check config を通します。
動作確認
cd ~/stacks/monitoring
docker compose ps
docker compose exec prometheus promtool query instant http://localhost:9090 'up'
curl -s http://127.0.0.1:9090/-/ready
curl -s http://192.168.10.5:3000/api/healthpromtool query instant の結果が up{host="pve1", instance="192.168.10.11:9100", job="node"} => 1 のように監視対象の数だけ並び、すべて => 1 であれば取得は成功しています。/-/ready は Prometheus Server is Ready. を返します。3000番の /api/health は、"database": "ok" と版(検証では 13.2.2)を含むJSONを返します。最後にブラウザでNode Exporter Fullのダッシュボードを開き、各パネルに値が入っていることを確認します。
よくある質問
GrafanaとPrometheusの違いは何ですか?
Prometheusは数値を集めて保存し、PromQLで計算し、アラートを判定する監視システムです。もう一方はその数値をグラフやダッシュボードとして表示するツールで、自分ではデータを集めず、PrometheusのほかにもLokiやInfluxDB、各種データベースなどを表示元にできます。
ZabbixとPrometheusの違いは何ですか?
Zabbixはエージェント、画面、通知までを1つの製品で持ち、テンプレートをGUIで当てて監視を組み立てます。後者は各ホストの /metrics を取りに行くプル型で、PromQLで自由に数値を組み合わせられ、コンテナやKubernetesとの相性が良い点が特徴です。可視化は通常Grafanaと組み合わせます。
Grafanaの料金はいくらですか?
自分でサーバーに入れて使うGrafana(オープンソース版、AGPLv3)は無料です。開発元のGrafana Labsは、クラウド版のGrafana Cloudと、サポート付きのEnterprise版を有料で提供しており、Grafana Cloudには使用量に上限のある無料枠もあります。料金と無料枠の条件は変わるので、執筆時点の公式サイトで確認してください。
Grafanaは日本語化されていますか?
されています。執筆時点のGrafana 13系には日本語の表示言語が同梱されていて、プロフィールの設定で言語を日本語に変えると、メニューや設定画面が日本語で表示されます。ただし、インポートしたダッシュボードのパネル名は作者が付けたものなので、英語のまま表示されます。
まとめ
監視サーバーにPrometheusとGrafanaをComposeで立て、各ホストにnode_exporterを入れれば、どの機械がいつ、どこで苦しくなったかをグラフで追えるようになります。最初に作るべきは、up による死活とディスク空き率の2つのアラートで、この2つだけでも「気づいたらディスクが満杯だった」事態の多くは防げます。9090番はローカルに閉じ、9100番は監視サーバーからだけ届くようにして、見る画面はGrafanaの3000番に絞ってください。