incus-contrib/notes/observability-guide.md

329 lines
9.6 KiB
Markdown

# Observability Stack — Prometheus, Grafana, Loki on Incus
A lightweight observability stack deployed as Incus containers on the lab
cluster. Provides metric collection (Prometheus), dashboards (Grafana),
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.
## Architecture
```mermaid
flowchart TD
lan(["LAN 192.168.103.0/24"])
subgraph fwd["OVN Forward · 192.168.103.201"]
fwd_grafana[":3000 → Grafana"]
fwd_prom[":9090 → Prometheus"]
end
subgraph mon["monitoring · 10.10.10.70 · oc-node-02"]
prometheus["Prometheus :9090"]
grafana["Grafana :3000"]
loki["Loki :3100<br/>gRPC :9096"]
promtail["Promtail"]
end
subgraph targets["Scrape Targets"]
incus["Incus nodes :8443<br/>.140 · .141 · .142"]
haproxy["HAProxy :8404<br/>.50 · .51"]
ne["node-exporters :9100<br/>.71 · .72 · .73"]
end
lan --> fwd
fwd --> mon
prometheus -->|"client cert"| incus
prometheus --> haproxy
prometheus --> ne
classDef external fill:#f5f5f5,color:#333,stroke:#999
classDef network fill:#0072B2,color:#fff,stroke:#005a8e
classDef mgmt fill:#CC79A7,color:#fff,stroke:#a36088
classDef instance fill:#56B4E9,color:#fff,stroke:#3a8fbf
classDef node fill:#009E73,color:#fff,stroke:#007a5e
class lan external
class fwd_grafana,fwd_prom network
class prometheus,grafana,loki,promtail mgmt
class incus,haproxy,ne instance
style fwd fill:#e0eef8,stroke:#0072B2
style mon fill:#f5e6f0,stroke:#CC79A7
style targets fill:#e0f2fe,stroke:#56B4E9
```
## Components
### Prometheus 2.54
Metric collection engine. Scrapes all targets at a 15-second interval.
- Stores metrics locally in the monitoring container
- Client certificate authentication for Incus `/1.0/metrics` endpoints
(uses cluster client cert + key)
- Plain HTTP scrape for HAProxy stats (`:8404/metrics`) and
node-exporters (`:9100/metrics`)
### Grafana 12.4
Dashboard and visualization frontend.
- Default credentials: `admin` / `admin`
- Pre-provisioned datasources for Prometheus and Loki
- Three dashboards deployed automatically (see Dashboards section)
- Accessible from LAN via OVN network forward
### Loki 3.6
Log aggregation backend.
- HTTP API on port 3100
- gRPC on port **9096** (not the default 9095 -- avoids conflict with
Promtail's own metrics port)
- 7-day retention policy
- Receives logs from Promtail running in the same container
### Promtail 3.6
Log shipping agent, co-located with Loki in the monitoring container.
- Pushes logs to Loki via gRPC on localhost:9096
- Scrapes container logs and system journal
### node_exporter
Host-level metrics via privileged Alpine containers.
- One container per cluster node, pinned with `--target` placement
- Privileged containers with host filesystem bind-mounts:
- `/proc` (host) -> `/host/proc` (read-only)
- `/sys` (host) -> `/host/sys` (read-only)
- `/` (host) -> `/host/rootfs` (read-only)
- Exposes standard node_exporter metrics on `:9100`
- Uses `monitoring-allow` ACL for network access
## Access
| Service | URL | Credentials |
|---------|-----|-------------|
| Grafana | http://192.168.103.201:3000 | `admin` / `admin` |
| Prometheus | http://192.168.103.201:9090 | None (open) |
Both services are accessible from the LAN through an OVN network forward
on IP `192.168.103.201`. The forward maps external ports directly to the
monitoring container's internal ports (no translation).
Prometheus and Loki are not exposed externally by default. They are
accessible only from within the OVN network or through the Grafana
datasource proxy.
## Dashboards
Three dashboards are provisioned automatically during deployment.
### Incus Cluster Overview
Visualizes metrics scraped from the Incus `/1.0/metrics` endpoint on each
cluster node.
- Instance CPU usage (per-instance, per-node)
- Memory usage and allocation
- Network I/O (bytes in/out per interface)
- Disk I/O (reads/writes, latency)
- Instance count and state
### HAProxy Traffic
Visualizes metrics from the HAProxy stats endpoint (`:8404/metrics`).
- Request rate (frontend and backend)
- Backend health status (UP/DOWN per server)
- Active sessions and session rate
- Traffic volume (bytes in/out)
- HTTP response codes (2xx, 4xx, 5xx)
- Connection errors and retries
### Host Resources
Visualizes metrics from node_exporter on each cluster node.
- CPU utilization (%)
- Memory utilization (%)
- Disk usage and I/O
- Network throughput per interface
- System load averages
- Filesystem free space
## ACL Configuration
Aether automatically creates per-instance ACLs with default-deny rules
for all containers on shared OVN networks. The observability stack needs
careful ACL configuration to allow scrape traffic.
### How Aether ACLs work
When Aether deploys a container, it creates ACLs with reject rules:
| Direction | Priority | Action | Effect |
|-----------|----------|--------|--------|
| Egress | 111 | reject | Blocks all outbound by default |
| Ingress | 100 | reject | Blocks all inbound by default |
These are OVN ACL rules enforced at the logical switch port level.
### monitoring-allow ACL
The observability containers use a `monitoring-allow` ACL with
`default.*.action=allow` set on all directions. This creates allow rules
at **priority 111** which matches or exceeds the Aether reject rules,
effectively overriding the default-deny policy.
All observability containers (monitoring, node-exp-01/02/03) have this
ACL applied.
### HAProxy scrape access
HAProxy containers are managed by Aether and have their own ACLs with
default-deny. For Prometheus to scrape HAProxy metrics on `:8404`, the
HAProxy Aether ACLs need **explicit ingress rules** allowing TCP traffic
from the monitoring container (10.10.10.70) to port 8404.
Without this, Prometheus targets for HAProxy will show as DOWN.
### NIC state after ACL changes
Changing `security.acls` on a container NIC can cause the NIC to go
**down**. After modifying ACLs, you may need to bring the NIC back up
manually or restart the container.
## Resource Budget
| Container | Image | RAM | Disk | Placement |
|-----------|-------|-----|------|-----------|
| monitoring | Debian/12 | 2 GiB | 20 GiB | oc-node-02 |
| node-exp-01 | Alpine | 128 MiB | — | oc-node-01 |
| node-exp-02 | Alpine | 128 MiB | — | oc-node-02 |
| node-exp-03 | Alpine | 128 MiB | — | oc-node-03 |
**Totals:**
- RAM: ~2.4 GiB (2 GiB + 3 x 128 MiB)
- Disk: 20 GiB (only the monitoring container needs significant storage)
- OVN forward IPs: 1 (192.168.103.201)
- OVN network IPs: 4 (10.10.10.70-73)
## Management
The `deploy-observability` script handles the full lifecycle.
### Deploy the stack
```bash
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.
### Check status
```bash
incusos/deploy-observability --status
```
Shows the state of all containers, scrape target health, Grafana
accessibility, and OVN forward configuration.
### Clean up
```bash
incusos/deploy-observability --cleanup
```
Removes all observability containers, the OVN network forward, and
associated ACLs. Does not affect monitored targets (Incus nodes,
HAProxy).
### Health check
```bash
incusos/deploy-observability --doctor
```
Verifies prerequisites, checks container health, validates Prometheus
targets are UP, confirms Grafana datasources are working, and reports
any ACL issues.
## Troubleshooting
### Targets show as DOWN in Prometheus
1. Check ACL rules on the target containers. Aether's default-deny ACLs
block all ingress including Prometheus scrapes.
2. Verify the NIC is up. Changing `security.acls` can bring the NIC down.
Check with `incus exec <container> -- ip link` and bring it up if needed.
3. For Incus node targets: verify the client certificate and key are
correctly placed in the Prometheus config directory and that the cert
is trusted by the cluster.
### Grafana can't reach Prometheus
Check that Prometheus is running and listening on localhost:9090 from
inside the monitoring container:
```bash
incus exec monitoring -- curl -s http://localhost:9090/-/healthy
```
If Prometheus is not running, check its service status:
```bash
incus exec monitoring -- systemctl status prometheus
```
### No node metrics
1. Verify the node-exporter containers are running and privileged:
```bash
incus list node-exp
```
2. Check that host filesystem mounts are in place:
```bash
incus exec node-exp-01 -- ls /host/proc/stat
```
3. Verify node_exporter is listening:
```bash
incus exec node-exp-01 -- wget -qO- http://localhost:9100/metrics | head
```
### HAProxy metrics show as invalid or empty
HAProxy needs the `prometheus-exporter` service enabled in its stats
configuration. The stats section in `haproxy.cfg` must include:
```
frontend stats
bind *:8404
http-request use-service prometheus-exporter if { path /metrics }
stats enable
stats uri /stats
```
Without the `use-service prometheus-exporter` directive, the `/metrics`
path returns HTML stats instead of Prometheus-format metrics.
### Loki not receiving logs
Verify Promtail can reach Loki on the gRPC port:
```bash
incus exec monitoring -- curl -s http://localhost:3100/ready
```
Note that Loki uses gRPC port **9096** in this deployment (not the
default 9095) to avoid conflicts with Promtail's metrics port.