# PostgreSQL + TimescaleDB Setup Anleitung fuer die Einrichtung von PostgreSQL mit TimescaleDB-Extension auf dem RMM-Backend-Server (192.168.85.13, Debian 13 Trixie). ## 1. PostgreSQL installieren ```bash # 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 ```bash # 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 ```bash # Als postgres User sudo -u postgres psql ``` ```sql -- Datenbank anlegen CREATE DATABASE rmm; -- User anlegen (Passwort anpassen!) CREATE USER rmm WITH PASSWORD 'Cynf0-RMM-2026!'; -- 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) ```bash # 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 ```bash psql -h 127.0.0.1 -U rmm -d rmm -c "SELECT version();" # Passwort: Cynf0-RMM-2026! 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 ```sql -- 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) ```sql -- 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) ```sql -- 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 ```sql -- 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) ```sql -- 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: ```yaml # Alte SQLite-Config entfernen: # db_path: "rmm.db" # Neue PostgreSQL-Config: database: host: "127.0.0.1" port: 5432 user: "rmm" password: "Cynf0-RMM-2026!" 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 ```sql -- 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 |