Keepalived

HA-Failover wird mit Hilfes des Virtual Router Redundancy Protocol (VRRP) implementiert. Keepalived bietet sowohl VRRP v2 und v3; der Artikel geht auf VRRP v2 ein.

VRRP verwendet das Konzept einer virtuellen IP-Adresse (VIP). Ein oder mehrere Hosts (Router, Server usw.) wählen einen Master-Host, der diese VIP kontrollieren soll. Fällt der Master aus, schaltet VRRP auf einen Standby-Host um.

Keepalived bietet neben der VRRP-Implementierung auch die Möglichkeit, Linux IP Virtual Servers (IPVS) für Load Balancing zu konfigurieren. Mit Keepalived lässt sich also auch ein redundanter Load Balancer konfigurieren.

VRRP wählt zunächst einen Master, der die virtuelle IP-Adresse erhalten soll. VRRP-Server werden mit einem Prioritätswert konfiguriert; der Server mit der höchsten Priorität bekommt die VRRP-Adresse zugewiesen. Alle anderen Server warten nun auf regelmässige Nachrichten des Masters, die anzeigen, dass dieser noch aktiv ist. Geht der Master offline, übernimmt der Server mit der nächsthöheren Priorität die VIP (der mittels Preemption auch automatisch zum Master werden kann).

Wenn ein Master-Server zum ersten Mal online geht und eine IP-Adresse übernimmt, sendet er eine Gratuitous ARP-Nachricht. Diese informiert andere Server über die mit der VIP verknüpften MAC-Adresse, so dass sie ihren Datenverkehr auf Schicht 2 korrekt adressieren können.

VRRP Advertisement

Sowohl die Ethernet- als auch die IP-Zieladresse sind Multicast-Adressen. Multicast-Verkehr wird immer an mehrere Hosts in einem Netzwerk gesendet, die diese Multicast-Adresse „abhören“. Da die meisten Netzwerke komplexe Multicast-Konfigurationen vermeiden, wird der Multicast-Verkehr für VRRP zu Broadcast-Verkehr auf dem lokalen Netzwerksegment.

VRRP ist weder TCP noch UDP, sondern verwendet das IP-Protokollnummer 112 (wichtig für die Konfiguration der Host-Firewalls).

Ein VRRP Advertisement-Paket enthält Informationen für die Wahl eines Masters als auch Angaben über den Master, die für die anderen Server wichtig sind:

  • Virtuelle Router-ID (VRID): Ein eindeutiger Bezeichner für eine VRRP-Instanz plus IP-Adressen (es kann mehr als eine geben) in einem Netzwerk. In Keepalived ist das die virtual_router_id-Direktive.

  • Priorität: Priorität des Hosts, der das Paket sendet. Sobald ein Master gewählt wurde, ist dies die Priorität, die der Master verwendet hat.

  • Auth Type und Authentication String: Enthalten ein einfaches Textpasswort, mit dem sich die Mitglieder der VRRP-Gruppe gegenseitig authentifizieren.

  • Advertisement Interval: Gibt an, wie oft der Master Advertisements sendet (meist 1x pro Sekunde).

  • IP Address: Enthält eine oder mehrere IP-Adressen, für die der Master zuständig ist.

Installation und Konfiguration

Keepalived findet sich in den Standard-Repos.

dnf -y install keepalived
keepalived --version
systemctl status keepalived

Zur Kommunikation zwischen den Hosts muss das Virtual Router Redundancy Protocol (VRRP) auf den Host-Firewalls freigegeben werden. VRRP nach RFC3768 arbeitet nicht direkt mit Ports, sondern mit der IP-Adresse 224.0.0.18 und dem gleichnamigen IP-Service (Protokoll-Nummer 112). firewalld oder iptables werden dafür wie folgt konfiguriert:

firewalld
firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
firewall-cmd --reload
iptables
iptables --append INPUT --protocol vrrp --jump ACCEPT
iptables-save > /etc/sysconfig/iptables
systemctl restart iptables

Im nachfolgenden Beispiel werden zwei Nodes konfiguriert. Einer wird initial Master, der andere ist Standby (Backup). Die Floating-IP ist 192.0.2.26. Beide authentifizieren sich untereinander per Passwort „1234“. Der Effekt: fällt der Master aus, erhält der zweite Node die Floating-IP. Zeigt der DNS für den Service auf die Floating-IP, ist der Service weiterhin erreichbar.

Damit System-Dienste primär die Floating-IP verwenden, muss dies noch konfiguriert werden:

echo 'net.ipv4.ip_nonlocal_bind = 1' >> /etc/sysctl.conf
sysctl -p

Konfiguration von Keepalived auf Node 1 (Master) - virtual_router_id und virtual_ipaddress müssen übereinstimmen:

/etc/keepalived/keepalived.conf
global_defs {
    notification_email {
        root@example.com
    }
    notification_email_from noreply@server01.example.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id server01
}

vrrp_instance VI_1 {
    state MASTER
    interface ens160
    virtual_router_id 51
    priority 255
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        192.0.2.26/24
    }
}

Konfiguration von Keepalived auf Node 2 (Backup):

/etc/keepalived/keepalived.conf
global_defs {
    notification_email {
        root@example.com
    }
    notification_email_from noreply@server02.example.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id server02
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens160
    virtual_router_id 51
    priority 254
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        192.0.2.26/24
    }
}

Hinweise zu den Direktiven:

  • advert_int ist das Advertisement-Intervall (hier 1x pro Sekunde).

  • priority kann zur Laufzeit geändert geändert werden.

  • state: Aus den verfügbaren Maschinen wird die mit der höchsten Priorität zum Master gewählt. Der Eintrag state spielt also an und für sich keine Rolle.

  • virtual_ipaddress ist die Floating/virtuelle IP.

Am Ende auf beiden:

systemctl enable --now keepalived

Die Floating-IP erscheint auf dem Server mit dem höchsten priority-Wert (der laut RFC bei 255 liegen sollte).

Firewalling:

  • Outbound: Source = MyHost, Dest = 224.0.0.18 (VRRP-IP), Service = Proto 112 (vrrp)

  • Inbound: Source = Keepalived-Neighbours, Dest = MyHost, Service = Proto 112 (vrrp)

Prozesse mit Keepalived tracken

Was, wenn ein App-Server netzwerktechnisch erreichbar ist, aber die darauf laufende Applikation nicht? Mit obigem Konzept wird dann kein neuer Master gewählt - aber auch dieses Szenario lässt sich mit Keepalived abfangen.

Beispiel: Failover auf Apache-Ebene mit Hilfe der track_process-Direktive.

/etc/keepalived/keepalived.conf
vrrp_track_process track_httpd {
    process httpd
    weight 10
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 244
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        192.0.2.26/24
    }
    track_process {
        track_httpd
    }
}

Der Server wird mit weight 10 und priority 244 die Priorität 10 + 244 = 254 advertisen. Wird der Apache gestoppt, fällt die Priorität auf 244, und ein Failover auslösen.

Dateien mit Keepalived tracken

Keepalived kann auch anhand von Dateiinhalten Prioritäten setzen (falls beispielsweise eine Applikation regelmässig ihren Gesundheitszustands-Code in einer Datei protokolliert).

/etc/keepalived/keepalived.conf
vrrp_track_file track_app_file {
    file /opt/my_app/my_health
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 244
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        192.0.2.26/24
    }
    track_file {
        track_app_file weight 1
    }
}

Wichtig: /opt/my_app/my_health wird durch Keepalived interpretiert. Ist der Inhalt der Datei track_app_file ungleich 0, wird der Wert aus der Datei mit track_app_file weight multipliziert. Enthält die Datei /opt/my_app/my_health eine 5, liegt die Priorität damit bei 5 * 1 + 244 = 249.

Interfaces mit Keepalived tracken

Beispiel: Load Balancer mit einer Frontend-VIP und einer Backend-Connection in das interne Netz soll nur dann ein Failover triggern, wenn das Backend down ist. Hier hilft track_interface:

/etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 244
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        192.0.2.26/24
    }
    track_interface {
        ens160 weight 5
    }
}

Die Priorität liegt damit bei 5 + 244, solange ens160 verfügbar ist, ansonsten fällt sie zurück auf 244.

Scripts mit Keepalived tracken

Angenommen, ein komplexeres Health-Script namens /usr/local/bin/keepalived_check.sh kommt zum Einsatz, welches 0 zurückgibt, wenn alles in Ordnung ist.

/etc/keepalived/keepalived.conf
vrrp_script keepalived_check {
    script "/usr/local/bin/keepalived_check.sh"
    interval 1
    timeout 5
    rise 3
    fall 3
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 244
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        192.0.2.26/24
    }
    track_script {
        keepalived_check
    }
}

Hinweise zu den Direktiven:

  • interval: Script läuft 1x pro Sekunde.

  • rise: Script muss 3x erfolgreich laufen, um als „healthy“ zu gelten.

  • fall: Script gilt nach 3 Timeouts oder nicht-erfolgreichen Läufen als „unhealthy“.

Notifications

Notification-Skripte helfen, bei Failover-Events Mails zu senden, abhängige Prozesse umzukonfigurieren, zu restarten etc. Alles, was es neben dem Skript (im Beispiel /usr/local/bin/keepalived_notify.sh) dazu braucht, ist eine notify-Anweisung in der vrrp_instance-Definition:

/etc/keepalived/keepalived.conf
...
vrrp_instance VI_1 {
    ...
    notify "/usr/local/bin/keepalived_notify.sh"
}

Das Notification-Script bekommt vier Variablen übergeben, die folgende Bedeutung haben:

  • $1: Instanz-Typ, z.B. INSTANCE

  • $2: Name der Instanz, z.B. VI_1

  • $3: aktueller state, z.B. MASTER

  • $4: aktuelle priority, z.B. 244

So sähe ein sinnvolles Notification-Script aus:

/usr/local/bin/keepalived_notify.sh
#!/usr/bin/env bash

logger "$1 $2 has transitioned to the $3 state with a priority of $4"

Ausgabe beispielsweise:

INSTANCE VI_1 has transitioned to the FAULT state with a priority of 244

Troubleshooting

tcpdump --interface any proto 112

Keepalived compilieren

# Install prerequisites
dnf -y install gcc openssl-devel

VER=2.2.7
wget https://www.keepalived.org/software/keepalived-$VER.tar.gz
tar -xf keepalived-$VER.tar.gz

cd keepalived-$VER
./configure
make
make install

keepalived --version

Built on 2024-04-18