Node_exporter
pg addon install nodeexporter runs node_exporter — the official Prometheus exporter that publishes the host’s CPU, memory, disk, network and filesystem metrics at /metrics — as a managed container from the official docker.io/prom/node-exporter image. Like Prometheus, VictoriaMetrics and Grafana it is a top-level addon: it describes the machine, not one PostgreSQL instance, so it is attached to none of them. It is the natural companion to a pgcli Prometheus addon — node_exporter exposes, Prometheus scrapes.
node_exporter shares VictoriaMetrics’s shape — single container, no config file (everything is CLI flags after the image name), no hot reload, no authentication — but it has one requirement no other web addon does, described below.
The non-negotiable: host mounts. A container reading its own
/procreports the CONTAINER’s metrics, not the host’s. To export the machine, pgcli hard-wires three read-only bind mounts — host/proc→/host/proc,/sys→/host/sys,/→/rootfs— and points the binary at them with--path.procfs/--path.sysfs/--path.rootfs. These are fixed in pgcli, not user-configurable; without them the addon would silently export the wrong numbers. They are mounted:roonly (never:z), so pgcli never relabels the host root filesystem.
There is NO login/password and no TLS. node_exporter just serves
/metricsin plain text. Because Prometheus scraping it is usually on a different host,Listendefaults to0.0.0.0— anyone who can reach the port can read detailed host facts (hardware, mounts, network). Restrict it to your monitoring network, or pass--listen 127.0.0.1for a same-host Prometheus.
Platform: Linux is the tested platform (the container uses host networking, so the exporter binds the host port directly). The design supports macOS (bridge + published port), but it has not been validated there yet.
Parameters
| Flag | Default | Description |
|---|---|---|
--name |
nodeexporter |
Instance name (map key) |
--image |
docker.io/prom/node-exporter:v1.12.1 |
Image override |
--port |
auto (base 9100) | Host port; auto-allocated from nodeexporter_start_port |
--listen |
0.0.0.0 |
Bind address — every interface by default (cross-host Prometheus); use 127.0.0.1 for loopback-only |
--extra-arg |
— | Extra CLI flag passed to the binary (repeatable); appended last so last-wins overrides earlier flags. E.g. --extra-arg --no-collector.cpufreq |
--force |
false | Recreate even when running — to apply changed ports / listen / extra-args |
node_exporter is stateless — it stores nothing, so there is no data directory. pg addon remove deletes only the container; reinstalling always starts fresh.
Install
The command pulls the image if needed, creates the container with the three host mounts, and prints the scrape URL:
Because the default bind is 0.0.0.0, the summary also prints an exposure warning and the matching Prometheus command. Verify the exporter serves real host numbers:
The values should track the host (free -b, cat /proc/loadavg) — if they track the container instead, a mount is missing (they cannot be, via pgcli, but a hand-run node_exporter often gets this wrong).
Wire it into Prometheus
The exporter is only useful once something scrapes it. A pgcli Prometheus instance does, via a one-line --scrape job (no service discovery, no Prometheus config edits):
To add this exporter to a pgcli Prometheus that is already running and already
scraping other jobs, use --scrape-append instead — it folds the node-exporter
job into the stored scrape list (merging same-named jobs, appending unseen ones)
and SIGHUP-reloads, so it never wipes the existing targets:
(A plain --scrape replaces the whole job set, so re-running install with it
would drop any other jobs p1 was scraping.) Then in Prometheus,
up{job="node-exporter"} is 1 and count(node_cpu_seconds_total) is large. See
the Prometheus addon for the full --scrape / --scrape-append
mechanics.
Re-running install on a running instance recreates it when the config changed (port, listen, extra-args), and leaves it alone otherwise; --force recreates even when unchanged. node_exporter has no SIGHUP reload, so every change requires container recreation.
Custom flags (--extra-arg)
node_exporter has dozens of collector flags. Toggle individual collectors off/on, or add --collector.*/--no-collector.* switches, via --extra-arg (repeatable):
Extra args are appended last to the command line, so they override pgcli’s injected defaults via last-wins (including pgcli’s own --collector.filesystem.mount-points-exclude, which drops the pseudo-filesystems pgcli just mounted so node_filesystem_* isn’t all noise). There is no config file to edit.
Listening and exposure
Listen defaults to 0.0.0.0: on Linux the container shares the host network namespace, so /metrics is reachable on every interface at the assigned port. This is deliberate — a Prometheus scraping node_exporter is usually on another machine. But there is no authentication, and node_exporter exposes fine-grained host detail (mount table, network interfaces, hardware). For a same-host Prometheus, pass --listen 127.0.0.1 (recreate with --force); otherwise restrict the port at the firewall. (Under the macOS bridge build, pgcli widens the bind to 0.0.0.0 automatically so the published port stays reachable through the podman VM.)
Ports
Each node_exporter instance owns a single port — the metrics endpoint — allocated from a pool with base nodeexporter_start_port (default 9100, node_exporter’s conventional port), incrementing for each additional instance and skipping ports taken by any managed container or used_ports. The allocation is saved to pg.yaml, so a reinstall never re-hands-out a port another addon holds. 9100 shares no number with Prometheus (9090), VictoriaMetrics (8428), Grafana (3000), Alertmanager (9093), or nginx (8080); an explicit --port still wins.
Configuration
There is no config file — everything is passed as CLI flags to the node_exporter binary, and the three host mounts are fixed by pgcli. extra_args is a list of flags appended last.
List
There are no credentials to reveal — node_exporter has none.
Start and stop
Containers run with podman’s unless-stopped restart policy, so they come back with podman after a host reboot. start/stop manage them explicitly:
Auto-start on Boot
To bring a node_exporter instance up on host boot:
This flags the instance in pg.yaml and installs/refreshes a boot service (a systemd --user unit on Linux, a LaunchAgent on macOS) that runs pg start --autostart. A boot-time start only brings the container up — node_exporter is stateless, so there is nothing to prepare. See Autostart for the full mechanism, status and disabling.
Remove
node_exporter keeps nothing on disk, so --clean-data has no effect beyond an informational note.
Logs
Troubleshooting
- Metrics look like the container’s, not the host’s — not possible via
pg addon install(the mounts are hard-wired), but if you ever runnode_exporterby hand you must pass the/proc//sys//read-only mounts and the matching--path.*flags. Confirm withcurl -s …/metrics | grep node_uname_infoand comparenode_memory_MemAvailable_bytesto the hostfree -b. - Prometheus shows the target DOWN — check the exporter is running (
pg addon list), that the scrape target address/port match (--scrape node-exporter=<host>:<port>), and that a loopback--listen 127.0.0.1exporter isn’t being scraped from another host. - A collector flag didn’t take effect —
--extra-argis applied at container creation. Reinstall with--forceto recreate, then checkpg logs addon nodeexporterfor the flag on the startup line. - Port already allocated — the assigned port is held in
pg.yamland skipped for later instances; free it withpg addon removefirst, or pick another with--port N.
Known limitations
- No authentication, no TLS. node_exporter serves plain-text
/metrics; the only protection for a0.0.0.0bind is the network boundary. Front with nginx or restrict by firewall if it must leave a trusted network. - Stateless — no data dir, no retention; nothing survives beyond the running process. Reinstall always starts fresh.
- Rootful assumption. The
-v /:/rootfs:romount reads the whole host tree; under rootless podman some host paths may be unreadable. All target VMs run rootful podman, matching the rest of pgcli. - pgcli does not validate
--extra-argvalues; a bad flag surfaces only in the container logs on startup. - On macOS the container runs inside the podman machine with the port published; validated on Linux only.