rmm2/docs/POSTGRES_SETUP.md

7.9 KiB

PostgreSQL + TimescaleDB Setup

Anleitung fuer die Einrichtung von PostgreSQL mit TimescaleDB-Extension auf dem RMM-Backend-Server (your-backend, Debian 13 Trixie).

1. PostgreSQL installieren

# Debian-Pakete
apt update
apt install -y postgresql postgresql-contrib postgresql-common

# Dienst starten und aktivieren
systemctl enable postgresql
systemctl start postgresql

# Version pruefen
psql --version
# Erwartet: psql (PostgreSQL) 17.x (Debian 13 Trixie liefert PG17)

2. TimescaleDB installieren

# TimescaleDB APT-Repository hinzufuegen
apt install -y curl gnupg
curl -s https://packagecloud.io/install/repositories/timescale/timescaledb/script.deb.sh | bash

# Bookworm-Repo verwenden (Trixie-Repo existiert noch nicht)
echo "deb https://packagecloud.io/timescale/timescaledb/debian/ bookworm main" \
  > /etc/apt/sources.list.d/timescaledb.list
curl -sL https://packagecloud.io/timescale/timescaledb/gpgkey | gpg --dearmor > /etc/apt/trusted.gpg.d/timescaledb.gpg
apt update

# WICHTIG: Version muss zur installierten PG-Version passen
# Pruefen: dpkg -l | grep postgresql-17 → z.B. 17.8
# Dann passende TimescaleDB-Version installieren:
apt install -y timescaledb-2-loader-postgresql-17=2.25.1~debian12-1708 \
               timescaledb-2-postgresql-17=2.25.1~debian12-1708

# shared_preload_libraries setzen
sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'timescaledb'/" \
  /etc/postgresql/17/main/postgresql.conf

# PostgreSQL neustarten
systemctl restart postgresql

3. Datenbank und User anlegen

# Als postgres User
sudo -u postgres psql
-- Datenbank anlegen
CREATE DATABASE rmm;

-- User anlegen (Passwort anpassen!)
CREATE USER rmm WITH PASSWORD 'YOUR_DB_PASSWORD';

-- Rechte vergeben
GRANT ALL PRIVILEGES ON DATABASE rmm TO rmm;

-- In die rmm-Datenbank wechseln
\c rmm

-- Schema-Rechte
GRANT ALL ON SCHEMA public TO rmm;

-- TimescaleDB Extension aktivieren
CREATE EXTENSION IF NOT EXISTS timescaledb;

-- Pruefen
\dx
-- Sollte timescaledb in der Liste zeigen

\q

4. pg_hba.conf anpassen (lokaler Zugriff)

# Zeile hinzufuegen (lokaler TCP-Zugriff fuer rmm User)
echo "host rmm rmm 127.0.0.1/32 scram-sha-256" >> /etc/postgresql/17/main/pg_hba.conf

# PostgreSQL neu laden
systemctl reload postgresql

5. Verbindung testen

psql -h 127.0.0.1 -U rmm -d rmm -c "SELECT version();"
# Passwort: YOUR_DB_PASSWORD

psql -h 127.0.0.1 -U rmm -d rmm -c "SELECT extname, extversion FROM pg_extension WHERE extname = 'timescaledb';"
# Sollte timescaledb mit Version zeigen

6. Schema anlegen

Das Backend legt die Tabellen automatisch beim Start an (Auto-Migration). Die Struktur:

Relationale Tabellen

-- Agent-Registry
CREATE TABLE IF NOT EXISTS agents (
    id TEXT PRIMARY KEY,
    name TEXT NOT NULL,
    hostname TEXT NOT NULL,
    ip TEXT NOT NULL,
    opnsense_version TEXT NOT NULL DEFAULT '',
    registered_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    last_heartbeat TIMESTAMPTZ
);

-- Config-Backups (versioniert, dedupliziert nach Hash)
CREATE TABLE IF NOT EXISTS config_backups (
    id SERIAL PRIMARY KEY,
    agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
    hash TEXT NOT NULL,
    size INTEGER NOT NULL,
    config_xml TEXT NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_config_backups_agent ON config_backups(agent_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_config_backups_hash ON config_backups(agent_id, hash);

TimescaleDB Hypertable (Metriken)

-- Metriken-Tabelle
CREATE TABLE IF NOT EXISTS metrics (
    time TIMESTAMPTZ NOT NULL,
    agent_id TEXT NOT NULL,
    metric TEXT NOT NULL,          -- z.B. 'cpu_usage', 'memory_used_percent', 'disk_used_percent'
    value DOUBLE PRECISION NOT NULL,
    tags JSONB                     -- z.B. {"interface":"igb0"}, {"disk":"/dev/ada0"}
);

-- In Hypertable umwandeln (automatische Partitionierung nach Zeit)
SELECT create_hypertable('metrics', 'time', if_not_exists => TRUE);

-- Index fuer schnelle Agent+Metrik-Abfragen
CREATE INDEX IF NOT EXISTS idx_metrics_agent_metric ON metrics(agent_id, metric, time DESC);

Systemdaten-Snapshots (aktueller Zustand)

-- Aktueller Snapshot der vollstaendigen Systemdaten (JSON)
CREATE TABLE IF NOT EXISTS system_data (
    agent_id TEXT PRIMARY KEY REFERENCES agents(id) ON DELETE CASCADE,
    data_json JSONB NOT NULL,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

7. Retention Policies einrichten

-- Metriken aelter als 90 Tage automatisch loeschen
SELECT add_retention_policy('metrics', INTERVAL '90 days');

-- Optional: Continuous Aggregate fuer stuendliche Durchschnitte
CREATE MATERIALIZED VIEW metrics_hourly
WITH (timescaledb.continuous) AS
SELECT
    time_bucket('1 hour', time) AS bucket,
    agent_id,
    metric,
    AVG(value) AS avg_value,
    MIN(value) AS min_value,
    MAX(value) AS max_value,
    COUNT(*) AS sample_count
FROM metrics
GROUP BY bucket, agent_id, metric
WITH NO DATA;

-- Automatisch aktualisieren
SELECT add_continuous_aggregate_policy('metrics_hourly',
    start_offset => INTERVAL '3 hours',
    end_offset => INTERVAL '1 hour',
    schedule_interval => INTERVAL '1 hour'
);

-- Stuendliche Aggregate 1 Jahr behalten
SELECT add_retention_policy('metrics_hourly', INTERVAL '365 days');

8. Compression aktivieren (optional, spart Speicher)

-- Compression fuer Metriken aelter als 7 Tage
ALTER TABLE metrics SET (
    timescaledb.compress,
    timescaledb.compress_segmentby = 'agent_id, metric',
    timescaledb.compress_orderby = 'time DESC'
);

SELECT add_compression_policy('metrics', INTERVAL '7 days');

9. Backend-Konfiguration

In der config.yaml des Backends:

# Alte SQLite-Config entfernen:
# db_path: "rmm.db"

# Neue PostgreSQL-Config:
database:
  host: "127.0.0.1"
  port: 5432
  user: "rmm"
  password: "YOUR_DB_PASSWORD"
  dbname: "rmm"
  sslmode: "disable"

10. Metriken die der Agent sendet

Bei jedem Heartbeat (alle 60s) werden folgende Metriken geschrieben:

Metrik Beschreibung Tags
cpu_usage CPU-Auslastung in Prozent
memory_used_percent RAM-Nutzung in Prozent
memory_used_bytes RAM genutzt in Bytes
memory_total_bytes RAM gesamt in Bytes
disk_used_percent Disk-Belegung pro Mountpoint {"mountpoint":"/", "dataset":"zroot/ROOT"}
uptime_seconds Uptime in Sekunden
interface_rx_bytes Empfangene Bytes pro Interface {"interface":"igb0"}
interface_tx_bytes Gesendete Bytes pro Interface {"interface":"igb0"}
gateway_rtt_ms Gateway RTT in ms {"gateway":"WAN_GW"}
gateway_loss_percent Gateway Paketverlust {"gateway":"WAN_GW"}

Nuetzliche Abfragen

-- CPU-Auslastung der letzten 24h (5-Minuten-Durchschnitt)
SELECT time_bucket('5 minutes', time) AS t,
       agent_id,
       AVG(value) AS cpu_avg
FROM metrics
WHERE metric = 'cpu_usage'
  AND time > NOW() - INTERVAL '24 hours'
GROUP BY t, agent_id
ORDER BY t;

-- Aktuelle Werte aller Agents
SELECT DISTINCT ON (agent_id, metric)
       agent_id, metric, value, time
FROM metrics
ORDER BY agent_id, metric, time DESC;

-- Disk-Warnung: > 80% belegt
SELECT agent_id, tags->>'mountpoint' AS mount,
       value AS used_percent, time
FROM metrics
WHERE metric = 'disk_used_percent'
  AND value > 80
  AND time > NOW() - INTERVAL '1 hour'
ORDER BY value DESC;

Zusammenfassung

Komponente Zweck
PostgreSQL 17 Relationale Daten (Agents, Backups)
TimescaleDB 2.x Time-Series Metriken (CPU, RAM, Disk, ...)
agents Agent-Registry
config_backups Versionierte Firewall-Configs
system_data Aktueller JSON-Snapshot
metrics Hypertable mit 60s-Aufloesung
metrics_hourly Continuous Aggregate (1h)
Retention Raw: 90 Tage, Hourly: 365 Tage
Compression Nach 7 Tagen automatisch