feat(cluster): PG Logical Replication + VIP/Keepalived + config_hash sync (v1.2.1–1.2.2)
- PG Logical Replication: edgeguard_shared PUBLICATION auf Primary, edgeguard_sub SUBSCRIPTION auf Secondary. Nur geteilte Config-Tabellen werden repliziert; node-eigene Daten (network_interfaces, ip_addresses, static_routes, cluster_settings, dns_settings, ntp_settings) bleiben lokal — OPNsense-Muster. - cluster-init-replication: Erstellt PUBLICATION, Rolle + pg_hba-Einträge (logical + replication), WAL-Level auf logical. - cluster-setup-standby: Erstellt SUBSCRIPTION (copy_data=true), pollt pg_subscription_rel bis alle Tabellen sync = 'r', rendert dann Configs. - promote: manueller Failover via pg_promote() + touch recovery.signal. - VIP/Keepalived: cluster_settings-Tabelle (vip_address, vip_interface, vrrp_router_id), /cluster/vip-settings API, Keepalived-Config-Generator mit VRRP + check_script + notify-Skripten in /usr/lib/edgeguard/scripts/. - config_hash sync: Secondary pusht alle 5 Min seinen Hash via mTLS an Primary (PushSelfToPrimary). Heartbeat schreibt nur LOCAL, daher ohne aktiven Push wäre Primary-Sicht des Secondary-Hash stale gewesen. - runSecondaryConfigRender: Goroutine auf Secondary rendert HAProxy+nftables neu wenn config_hash sich ändert (Logical-Replication-Nachzügler). - confighash: node-spezifische Tabellen aus hashSpec entfernt. - postinst: Keepalived-Skripte installieren, sudoers für keepalived. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
36
internal/database/migrations/0029_cluster_vip.sql
Normal file
36
internal/database/migrations/0029_cluster_vip.sql
Normal file
@@ -0,0 +1,36 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
-- pg_role: Rolle dieser Node in der PG-Replikation.
|
||||
-- "standalone" = kein Streaming-Replication-Setup
|
||||
-- "primary" = WAL-Sender, repliziert an Standby(s)
|
||||
-- "standby" = Hot-Standby, liest WAL vom Primary
|
||||
ALTER TABLE ha_nodes ADD COLUMN IF NOT EXISTS pg_role TEXT NOT NULL DEFAULT 'standalone';
|
||||
|
||||
-- cluster_settings: VIP + VRRP-Konfiguration (Singleton, id=1).
|
||||
-- vip_address = die virtuelle IP-Adresse (z.B. "89.163.205.10")
|
||||
-- vip_interface = Netzwerk-Interface (z.B. "eth0")
|
||||
-- vip_auth_pass = VRRP-Authentication-Passwort (max. 8 Zeichen, Keepalived-Limit)
|
||||
-- vrrp_router_id = VRRP Virtual Router ID (1–255, muss im Subnetz eindeutig sein)
|
||||
CREATE TABLE IF NOT EXISTS cluster_settings (
|
||||
id INTEGER PRIMARY KEY DEFAULT 1,
|
||||
vip_address TEXT,
|
||||
vip_interface TEXT,
|
||||
vip_auth_pass TEXT,
|
||||
vrrp_router_id INTEGER NOT NULL DEFAULT 51,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT cluster_settings_singleton CHECK (id = 1)
|
||||
);
|
||||
|
||||
INSERT INTO cluster_settings (id) VALUES (1) ON CONFLICT DO NOTHING;
|
||||
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
|
||||
DROP TABLE IF EXISTS cluster_settings;
|
||||
ALTER TABLE ha_nodes DROP COLUMN IF EXISTS pg_role;
|
||||
|
||||
-- +goose StatementEnd
|
||||
Reference in New Issue
Block a user