feat(keepalived): VIP wandert zum PG-Primary zurück (preempt_delay) — v1.3.9
Bisher trugen beide VRRP-Instanzen `nopreempt` → ein erholter Primary holte die VIP NICHT zurück; nach einem Deploy-/VM-Blip blieb sie auf dem Standby kleben (genau die Situation: VIP auf utm-2 obwohl utm-1 der PG-Primary ist). Jetzt: der bevorzugte Node (PG-Primary, Prio 200) rendert `preempt_delay 120` statt nopreempt → er holt die VIP nach 120s STABILER Erholung heim. Der Standby (Prio 100) behält nopreempt (reißt die VIP nie an sich → Split-Brain-Schutz). Der 120s-Delay + gw-check + Heartbeat-Sync-Group verhindern Flap-Back bei kurzen Hicks. State bleibt immer BACKUP. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,12 @@ var cfgTpl string
|
||||
|
||||
var tpl = template.Must(template.New("keepalived").Parse(cfgTpl))
|
||||
|
||||
// preemptDelaySeconds: wie lange der bevorzugte Node (PG-Primary, Prio 200)
|
||||
// nach seiner Erholung STABIL sein muss, bevor er die VIP zurückholt. Lang
|
||||
// genug, dass ein kurzer Deploy-/VM-Hick keinen sofortigen Flap-Back auslöst,
|
||||
// kurz genug, dass die VIP zeitnah zum Primary heimwandert.
|
||||
const preemptDelaySeconds = 120
|
||||
|
||||
// VIPEntry ist eine einzelne VIP-Adresse die keepalived verwaltet.
|
||||
type VIPEntry struct {
|
||||
Address string // z.B. 89.163.205.100
|
||||
@@ -47,6 +53,10 @@ type View struct {
|
||||
PeerIP string // Peer-Public-IP (unicast_peer)
|
||||
AuthPass string
|
||||
VIPs []VIPEntry // alle is_vip=true Einträge aus ip_addresses
|
||||
// PreemptDelay > 0: dieser Node holt die VIP nach `preempt_delay`
|
||||
// Sekunden stabiler Erholung zurück (nur der bevorzugte PG-Primary,
|
||||
// Prio 200). 0 = nopreempt (Standby reißt die VIP nie an sich).
|
||||
PreemptDelay int
|
||||
// Dual-path VRRP (Split-Brain-Schutz, Migration 0033)
|
||||
HBInterface string
|
||||
HBSrcIP string
|
||||
@@ -167,18 +177,25 @@ func (g *generator) buildView(cs *models.ClusterSettings, vips []VIPEntry, local
|
||||
v.HBRouterID = 52
|
||||
}
|
||||
|
||||
// State IMMER BACKUP: das Template setzt `nopreempt`, und nopreempt wirkt
|
||||
// in keepalived NUR, wenn die Instanz im BACKUP-Zustand startet (bei state
|
||||
// MASTER wird nopreempt ignoriert). Die Priorität entscheidet weiterhin die
|
||||
// Initial-Election (primary=200 gewinnt), aber ein erholter Node reißt die
|
||||
// VIP NICHT mehr zurück → kein Flap-Back / Split-Brain. Deckt sich mit der
|
||||
// "kein Auto-Promote"-Philosophie: Promotion bleibt manuell.
|
||||
// pg_role=standby ist das härtere Signal (Standby ist nie bevorzugter Node).
|
||||
// State IMMER BACKUP (kein Node startet als MASTER — sonst würde
|
||||
// nopreempt/preempt_delay ignoriert). Die Priorität entscheidet die
|
||||
// Election: der PG-Primary (200) ist der bevorzugte VIP-Home-Node.
|
||||
//
|
||||
// Preemption-Strategie:
|
||||
// - Bevorzugter Node (Prio 200, PG-Primary): `preempt_delay` — holt die
|
||||
// VIP nach preemptDelaySeconds STABILER Erholung zurück. So „wandert"
|
||||
// die VIP nach einem Failover/Deploy-Blip von selbst wieder heim zum
|
||||
// Primary (gewünschtes Verhalten), aber der Delay + gw-check +
|
||||
// Heartbeat verhindern Flap-Back bei kurzen Hicks.
|
||||
// - Standby (Prio 100): `nopreempt` — reißt die VIP NIE an sich
|
||||
// (Split-Brain-Schutz; Promotion zum Primary bleibt manuell).
|
||||
// pg_role=standby ist das härtere Signal (Standby ist nie bevorzugt).
|
||||
v.State = "BACKUP"
|
||||
if local.PGRole == "standby" {
|
||||
v.Priority = 100
|
||||
} else if local.PGRole == "primary" || local.Role == "primary" {
|
||||
v.Priority = 200
|
||||
v.PreemptDelay = preemptDelaySeconds
|
||||
} else {
|
||||
v.Priority = 100
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user