Update observability guide and refresh all dashboard screenshots
Guide changes: - Architecture diagram now shows auto-discovered targets and optional oc-server monitoring - Fix /host/rootfs → /host/root mount path in node_exporter section - Document ARGS variable name (not NODE_EXPORTER_OPTS) for Alpine init - Add --oc-server and --nodes flag documentation to Management section - Update resource budget with oc-server row - Expand "No node metrics" troubleshooting with ARGS diagnostic steps - Update screenshot captions with correct RAM values (19.5 GiB) Screenshots refreshed after fixing node-exporter RAM bug — all 9 dashboards now show correct host metrics (20 GiB RAM, not 128 MiB). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
@ -6,8 +6,10 @@ and log aggregation (Loki) for Incus nodes, HAProxy load balancers, and
|
|||
host-level resources.
|
||||
|
||||
The stack runs entirely on OVN and is managed by the `deploy-observability`
|
||||
script. All containers use the `monitoring-allow` ACL to permit scrape
|
||||
traffic on the shared network.
|
||||
script. Cluster nodes are **auto-discovered** — the script queries
|
||||
`incus cluster list` to find nodes, eliminating hardcoded IPs. All
|
||||
containers use the `monitoring-allow` ACL to permit scrape traffic on the
|
||||
shared network.
|
||||
|
||||
## Architecture
|
||||
|
||||
|
|
@ -27,10 +29,15 @@ flowchart TD
|
|||
promtail["Promtail"]
|
||||
end
|
||||
|
||||
subgraph targets["Scrape Targets"]
|
||||
incus["Incus nodes :8443<br/>.140 · .141 · .142"]
|
||||
subgraph targets["Scrape Targets (auto-discovered)"]
|
||||
incus["Incus nodes :8443<br/>auto-discovered from cluster"]
|
||||
haproxy["HAProxy :8404<br/>.50 · .51"]
|
||||
ne["node-exporters :9100<br/>.71 · .72 · .73"]
|
||||
ne["node-exporters :9100<br/>one per cluster node (OVN)"]
|
||||
end
|
||||
|
||||
subgraph ocserver["oc-server (optional, --oc-server)"]
|
||||
oc_incus["Incus API :8443<br/>192.168.102.120"]
|
||||
oc_ne["node-exporter :9100<br/>proxy device on host IP"]
|
||||
end
|
||||
|
||||
lan --> fwd
|
||||
|
|
@ -38,6 +45,8 @@ flowchart TD
|
|||
prometheus -->|"client cert"| incus
|
||||
prometheus --> haproxy
|
||||
prometheus --> ne
|
||||
prometheus -->|"client cert"| oc_incus
|
||||
prometheus --> oc_ne
|
||||
|
||||
classDef external fill:#f5f5f5,color:#333,stroke:#999
|
||||
classDef network fill:#0072B2,color:#fff,stroke:#005a8e
|
||||
|
|
@ -49,10 +58,12 @@ flowchart TD
|
|||
class fwd_grafana,fwd_prom network
|
||||
class prometheus,grafana,loki,promtail mgmt
|
||||
class incus,haproxy,ne instance
|
||||
class oc_incus,oc_ne node
|
||||
|
||||
style fwd fill:#e0eef8,stroke:#0072B2
|
||||
style mon fill:#f5e6f0,stroke:#CC79A7
|
||||
style targets fill:#e0f2fe,stroke:#56B4E9
|
||||
style ocserver fill:#e0f5ed,stroke:#009E73
|
||||
```
|
||||
|
||||
## Components
|
||||
|
|
@ -97,13 +108,18 @@ Log shipping agent, co-located with Loki in the monitoring container.
|
|||
|
||||
Host-level metrics via privileged Alpine containers.
|
||||
|
||||
- One container per cluster node, pinned with `--target` placement
|
||||
- One container per cluster node, auto-discovered and pinned with `--target`
|
||||
- Privileged containers with host filesystem bind-mounts:
|
||||
- `/proc` (host) -> `/host/proc` (read-only)
|
||||
- `/sys` (host) -> `/host/sys` (read-only)
|
||||
- `/` (host) -> `/host/rootfs` (read-only)
|
||||
- `/` (host) -> `/host/root` (read-only)
|
||||
- Configured via `/etc/conf.d/node-exporter` with `ARGS="--path.procfs=/host/proc
|
||||
--path.sysfs=/host/sys --path.rootfs=/host/root"` (Alpine's init script reads
|
||||
the `ARGS` variable, not `NODE_EXPORTER_OPTS`)
|
||||
- Exposes standard node_exporter metrics on `:9100`
|
||||
- Uses `monitoring-allow` ACL for network access
|
||||
- Optional: oc-server gets its own node-exporter with a proxy device
|
||||
exposing `:9100` on the host IP (since oc-server uses incusbr0, not OVN)
|
||||
|
||||
## Access
|
||||
|
||||
|
|
@ -147,7 +163,8 @@ Overview of all instances with instance/node template variables.
|
|||
|
||||

|
||||
*Cluster-wide view showing 8 instances across 3 nodes with 28 total CPUs,
|
||||
active memory utilization, and the instance status table.*
|
||||
20.4 GiB total memory, cluster memory utilization gauge, and the instance
|
||||
status table with per-instance drill-down links.*
|
||||
|
||||
### Incus Cluster — Instance Deep Dive
|
||||
|
||||
|
|
@ -190,8 +207,9 @@ Physical host monitoring with node template variable.
|
|||
- Network traffic by device, network errors and drops
|
||||
|
||||

|
||||
*Host-level metrics from node-exporter showing system info, CPU/memory
|
||||
breakdown, filesystem usage, and network traffic for all 3 IncusOS nodes.*
|
||||
*Host-level metrics from node-exporter showing system info (19.5 GiB RAM per
|
||||
node, kernel version, boot time), CPU usage/mode breakdown, load average, and
|
||||
memory utilization for all 3 auto-discovered IncusOS nodes.*
|
||||
|
||||
### Incus Infrastructure — Storage & Filesystem
|
||||
|
||||
|
|
@ -280,8 +298,9 @@ Prometheus self-monitoring (no template variables).
|
|||
- TSDB size trend, samples ingested trend, compactions
|
||||
|
||||

|
||||
*Prometheus self-monitoring showing 7 targets UP (3 Incus, 3 node-exporter,
|
||||
1 self), 2 DOWN (HAProxy), scrape performance, and TSDB stats.*
|
||||
*Prometheus self-monitoring showing 7 targets UP (3 Incus nodes, 3
|
||||
node-exporters with friendly names, 1 self), 2 DOWN (HAProxy not deployed),
|
||||
scrape duration by job, and samples scraped.*
|
||||
|
||||
### Incus Operations — Capacity Planning
|
||||
|
||||
|
|
@ -293,8 +312,8 @@ Resource planning with 7-day default time range (no template variables).
|
|||
- Instance count trend, memory allocation vs active memory per instance
|
||||
|
||||

|
||||
*Capacity planning with CPU/memory headroom bars, 7-day usage trends, 30-day
|
||||
disk space forecast using predict_linear, and instance count over time.*
|
||||
*Capacity planning with CPU/memory headroom bars per node, 7-day CPU and
|
||||
memory usage trends, and 30-day disk space forecast using predict_linear.*
|
||||
|
||||
## ACL Configuration
|
||||
|
||||
|
|
@ -340,6 +359,8 @@ manually or restart the container.
|
|||
|
||||
## Resource Budget
|
||||
|
||||
Node-exporter containers are auto-discovered from the cluster — one per node.
|
||||
|
||||
| Container | Image | RAM | Disk | Placement |
|
||||
|-----------|-------|-----|------|-----------|
|
||||
| monitoring | Debian/12 | 2 GiB | 20 GiB | oc-node-02 |
|
||||
|
|
@ -347,6 +368,12 @@ manually or restart the container.
|
|||
| node-exp-02 | Alpine | 128 MiB | — | oc-node-02 |
|
||||
| node-exp-03 | Alpine | 128 MiB | — | oc-node-03 |
|
||||
|
||||
**OC server monitoring** (optional, deployed via `--oc-server`):
|
||||
|
||||
| Container | Image | RAM | Placement | Notes |
|
||||
|-----------|-------|-----|-----------|-------|
|
||||
| node-exp-oc-server | Alpine | 128 MiB | oc-server | Proxy device exposes :9100 on host IP |
|
||||
|
||||
**Dummy workloads** (optional, deployed via `--workloads`):
|
||||
|
||||
| Container | Image | RAM | Placement | Purpose |
|
||||
|
|
@ -355,14 +382,15 @@ manually or restart the container.
|
|||
| workload-api | Alpine | 128 MiB | oc-node-03 | Python HTTP + memory sawtooth |
|
||||
|
||||
**Totals:**
|
||||
- RAM: ~2.4 GiB core (2 GiB + 3 x 128 MiB), +256 MiB with workloads
|
||||
- RAM: ~2.4 GiB core (2 GiB + 3 x 128 MiB), +128 MiB with oc-server, +256 MiB with workloads
|
||||
- Disk: 20 GiB (only the monitoring container needs significant storage)
|
||||
- OVN forward IPs: 1 (192.168.103.201)
|
||||
- OVN network IPs: 4 core (10.10.10.70-73), +2 with workloads (.80, .81)
|
||||
|
||||
## Management
|
||||
|
||||
The `deploy-observability` script handles the full lifecycle.
|
||||
The `deploy-observability` script handles the full lifecycle. Cluster nodes
|
||||
are **auto-discovered** from `incus cluster list` — no hardcoded IPs needed.
|
||||
|
||||
### Deploy the stack
|
||||
|
||||
|
|
@ -370,10 +398,27 @@ The `deploy-observability` script handles the full lifecycle.
|
|||
incusos/deploy-observability --deploy
|
||||
```
|
||||
|
||||
Creates the monitoring container and all node-exporter containers,
|
||||
installs and configures Prometheus, Grafana, Loki, and Promtail,
|
||||
provisions dashboards, sets up the OVN network forward, and configures
|
||||
ACLs.
|
||||
Auto-discovers cluster nodes, creates the monitoring container and one
|
||||
node-exporter per node, installs and configures Prometheus, Grafana,
|
||||
Loki, and Promtail, provisions dashboards, sets up the OVN network
|
||||
forward, and configures ACLs.
|
||||
|
||||
To also monitor the standalone OC management server:
|
||||
|
||||
```bash
|
||||
incusos/deploy-observability --deploy --oc-server 192.168.102.120
|
||||
```
|
||||
|
||||
This deploys an additional node-exporter on oc-server with a proxy device
|
||||
to expose `:9100` on the host IP (since oc-server uses incusbr0, not OVN).
|
||||
Requires an `oc-server` Incus remote — the script provides `incus remote add`
|
||||
instructions if it's missing.
|
||||
|
||||
To override auto-discovery with a manual node list:
|
||||
|
||||
```bash
|
||||
incusos/deploy-observability --deploy --nodes oc-node-01,oc-node-02,oc-node-03
|
||||
```
|
||||
|
||||
### Deploy dummy workloads
|
||||
|
||||
|
|
@ -447,7 +492,7 @@ If Prometheus is not running, check its service status:
|
|||
incus exec monitoring -- systemctl status prometheus
|
||||
```
|
||||
|
||||
### No node metrics
|
||||
### No node metrics (or RAM shows 128 MiB)
|
||||
|
||||
1. Verify the node-exporter containers are running and privileged:
|
||||
```bash
|
||||
|
|
@ -457,7 +502,19 @@ incus exec monitoring -- systemctl status prometheus
|
|||
```bash
|
||||
incus exec node-exp-01 -- ls /host/proc/stat
|
||||
```
|
||||
3. Verify node_exporter is listening:
|
||||
3. Verify node_exporter is running with host path flags:
|
||||
```bash
|
||||
incus exec node-exp-01 -- ps aux | grep node_exporter
|
||||
# Should show: --path.procfs=/host/proc --path.sysfs=/host/sys --path.rootfs=/host/root
|
||||
```
|
||||
4. If flags are missing, check `/etc/conf.d/node-exporter` uses `ARGS=`
|
||||
(not `NODE_EXPORTER_OPTS=`). Alpine's init script reads the `ARGS`
|
||||
variable:
|
||||
```bash
|
||||
incus exec node-exp-01 -- cat /etc/conf.d/node-exporter
|
||||
# Should show: ARGS="--path.procfs=/host/proc ..."
|
||||
```
|
||||
5. Verify node_exporter is listening:
|
||||
```bash
|
||||
incus exec node-exp-01 -- wget -qO- http://localhost:9100/metrics | head
|
||||
```
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 205 KiB |
|
Before Width: | Height: | Size: 214 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 229 KiB After Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 349 KiB After Width: | Height: | Size: 352 KiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 58 KiB |