Testing the consolidated litellm-self-heal contract against live infra found: - IP drift: pi host is .24, not .65 (confused with ra-h-os bridge) - Fixed gpu-monitor.prose.md: 192.168.68.65 → 192.168.68.24 (3 locations) - Fixed gpu-fleet.prose.md: .65 → .24 in config files + agent keys tables - Container count: 10 running on CT 116, not 8 as contract stated - Added harness-docker-stats + harness-pve-exporter to litellm-self-heal - Updated container health check list Verified: GPU monitor restarted on .24:9100, ornith model inference working, all 10 containers healthy.
137 lines
5.9 KiB
Markdown
137 lines
5.9 KiB
Markdown
---
|
|
kind: responsibility
|
|
name: gpu-monitor
|
|
description: >
|
|
Comprehensive GPU fleet monitor — polls every subsystem (sidecars, router,
|
|
LiteLLM, Strix Halo, dashboard) every 15s, renders a live HTML dashboard,
|
|
checks alert thresholds, and exposes a JSON API for downstream consumers.
|
|
agent: abiba
|
|
---
|
|
|
|
## Maintains
|
|
|
|
- gpu-fleet-data: { gpus: array, strix: object, router: object, litellm: object, summary: object, alerts: array } — Full fleet snapshot refreshed every 15s
|
|
- dashboard: live HTML at `/root/dashboard/gpu-fleet.html`, served on port 9100
|
|
- gpu-data-api: JSON at `GET /gpu-data` on port 9100
|
|
- health-endpoint: `GET /health` on port 9100 → 200 if cache populated, 503 if warming up
|
|
|
|
## GPU Fleet Topology
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ GPU Monitor Server (:9100) — 192.168.68.24 │
|
|
│ Polls every 15s, serves dashboard + JSON API │
|
|
└──┬──────────┬──────────┬────────────────────────────────┘
|
|
│ │ │
|
|
▼ ▼ ▼
|
|
┌──────┐ ┌──────┐ ┌────────┐
|
|
│.8:8080│ │.110 │ │.116:80 │
|
|
│RTX3090│ │:8080 │ │nginx │
|
|
│gemma │ │RTX5070│ │router │
|
|
└──────┘ │qwen27B│ │LiteLLM │
|
|
└──────┘ │dashboard│
|
|
└────────┘
|
|
|
|
Note: JSON sidecar exporters at :8090 were never deployed on any
|
|
GPU host. Router falls back to GPU /health direct probe. Monitor
|
|
should use router /health/unified as source of truth for GPU status.
|
|
Strix Halo :8080 is firewalled to .116 only — monitor on .24 cannot
|
|
poll .15:8080 directly; must go through router on .116.
|
|
```
|
|
|
|
### Subsystems Polled
|
|
|
|
| Subsystem | Endpoint | Frequency | Metrics |
|
|
|-----------|----------|-----------|---------|
|
|
| GPU Status (all, via router) | `http://192.168.68.116/health/unified` | 15s | models, CB, scores, GPU status (router probes each GPU /health directly) |
|
|
| Router (unified) | `http://192.168.68.116/health/unified` | 15s | models, CB, scores, GPU status |
|
|
| Router (basic) | `http://192.168.68.116/health` | 15s | basic aliveness |
|
|
| LiteLLM | `http://192.168.68.116/litellm/health` | 15s | proxy health, model count |
|
|
| Strix Halo | `http://192.168.68.116/health/unified` (router) | 15s | ornith status via router — cannot poll .15:8080 directly (firewalled to .116 only) |
|
|
| Dashboard | `http://192.168.68.116/dashboard/` | 15s | harness-dashboard aliveness |
|
|
|
|
### Alert Delivery
|
|
|
|
All alerts are sent to `#agent-hub` stream topics:
|
|
- `alerts-gpu` — GPU fleet alerts (temp, VRAM, utilization)
|
|
- `alerts-pm2` — PM2 process health (restarts, crashes)
|
|
- `alerts-infra` — Infrastructure health (LiteLLM, Zulip, containers)
|
|
|
|
This replaces the previous DM-only delivery. All agents on the mesh can see and respond to alerts.
|
|
|
|
## Alert Thresholds
|
|
|
|
| Metric | Warning | Critical |
|
|
|--------|---------|----------|
|
|
| GPU Temp | >80°C | >90°C |
|
|
| VRAM Usage | >90% | >95% |
|
|
| GPU Util | >95% | >98% |
|
|
| Sidecar Unreachable | — | info (sidecars not deployed — use router /health/unified) |
|
|
| Model Down | — | critical (circuit breaker open) |
|
|
|
|
### JSON API Response Schema (/gpu-data)
|
|
|
|
```json
|
|
{
|
|
"gpus": [{ "name", "gpu_name", "temp_c", "vram_used_mb", "vram_total_mb",
|
|
"gpu_util_pct", "power_w", "power_limit_w", "fan_pct",
|
|
"models", "hostname", "active_requests", "health_score",
|
|
"circuit_open" }],
|
|
"strix": { "status", "cpu_load", "llama_health" },
|
|
"router": { "available_models", "circuit_breaker", "gpus", "scores",
|
|
"status", "redis", "_basic" },
|
|
"litellm": { ... },
|
|
"dashboard": { "reachable": bool },
|
|
"summary": { "fleet_status", "models_available", "models_total",
|
|
"circuit_breakers_open", "gpu_count", "gpu_errors",
|
|
"strix_running", "router_reachable", "litellm_reachable" },
|
|
"alerts": [{ "gpu", "metric", "level", "value", "threshold" }],
|
|
"updated": "ISO8601",
|
|
"monitor_version": "2.0.0"
|
|
}
|
|
```
|
|
|
|
## Operations
|
|
|
|
### list
|
|
`curl http://localhost:9100/gpu-data | jq` — Full fleet status
|
|
|
|
### check-health
|
|
`curl http://localhost:9100/health` — Monitor self-check
|
|
|
|
### view-dashboard
|
|
Open `http://localhost:9100/` in browser — Live HTML dashboard
|
|
|
|
### restart
|
|
```bash
|
|
pkill -f gpu-monitor-server.py
|
|
python3 /root/scripts/gpu-monitor-server.py &
|
|
```
|
|
Or via PM2: `pm2 restart gpu-monitor`
|
|
|
|
### check-router
|
|
The router health is accessed through nginx on port 80 (NOT port 9000 directly).
|
|
`curl http://192.168.68.116/health/unified` — Router unified health via nginx proxy
|
|
`curl http://192.168.68.116:9000/health/unified` — ❌ WILL FAIL (port bound to 127.0.0.1 only)
|
|
|
|
## Configuration Files
|
|
|
|
| File | Host | Purpose |
|
|
|------|------|---------|
|
|
| `/root/scripts/gpu-monitor-server.py` | pi (.24) | Monitor server v2.0.0 |
|
|
| `/root/dashboard/gpu-fleet.html` | pi (.24) | Live HTML dashboard |
|
|
| `/etc/nginx/nginx.conf` | CT 116 | Routes /health/* → router |
|
|
|
|
## Execution
|
|
|
|
1. **Poll router** (every 15s): GET .116/health/unified — single source of truth for all GPU status (router probes each GPU /health directly via sidecar fallback)
|
|
2. **Poll router** (every 15s): GET .116/health via nginx:80
|
|
3. **Poll LiteLLM** (every 15s): GET .116/litellm/health via nginx:80
|
|
4. **Poll Strix** (every 15s): via router /health/unified (cannot poll .15:8080 directly — firewalled to .116 only)
|
|
5. **Poll dashboard** (every 15s): GET .116/dashboard/
|
|
6. **Check alerts**: Compare metrics against thresholds
|
|
7. **Compute summary**: Fleet-wide health aggregation
|
|
8. **Render dashboard**: Generate HTML at /root/dashboard/gpu-fleet.html
|
|
9. **Serve API**: HTTP server on port 9100
|
|
10. **Repeat** every 15 seconds
|