Was im großen geht, das geht natürlich auch im Kleinen.
Da sich meine Bastelaktivitäten mit dem Raspberry Pi mit der Zeit immer mehr eingestellt haben, da einige Projekte umgesetzt und andere wiederum im Sande verlaufen sind, stellte sich die Frage, was man denn nun mit den kleinen Rechenzwergen anfangen könnte. Zum brach rumliegen sind sie ja definitiv zu schade 😉
Da ich es immer schon ein wenig n3rd1g fand ein Webprojekt direkt von daheim zu hosten und das ganze möglichst ausfallsicher zu gestalten, entschied ich mich dazu einen kleinen Blog auf meinen RPi’s zu betreiben.
Damit alle meine Pi’s eine sinnvolle Tätigkeit bekommen, entschied ich mich einen Loadbalancer auf dem einen zu installieren und die restlichen zwei als „App-Server“ laufen zu lassen.
Hierbei ist die Software IPVS in Verbindung mit dem Ldirectord auf jeden Fall eine gute Wahl. Ldirectord ist ein Daemon, welcher mit IPVS spricht und noch viele Funktionen mitbringt, die IPVS von Hause aus nicht abdecken kann, wie zum Beispiel das automatische Herausnehmen eines Servers aus einem Load Balancing Pool, wenn dieser nicht den gewünschten Content ausliefert.
Es stehen mehrere Möglichkeiten zur Auswahl, wie der Load Balancer mit den Real-Servern (also unsere App-Server) die Daten austauschen kann. Die wichtigsten stellen wohl das Direct-Routing und das Masquerading dar.
In diesem Beispiel habe ich mich für Direct-Routing entschieden, da Masquerading doch zu einem Teil auf die Rechenleistung des Raspberry’s niederschlägt.
Auf dem Loadbalancer reicht es aus, wenn das Paket ldirectord installiert wird. Alle benötigten Abhängigkeiten wie IPVS werden automatisch mit installiert.

Konfiguration ldirectord

Nach abgeschlossener Installation muss zunächst die Datei /etc/default/ldirectord angepasst werden. Hier wird über die Variable „CONFIG_FILE“ der Ort der Config definiert:

# Set the following variable to define a default configuration
# file for ldirectord.
CONFIG_FILE=/etc/ldirectord.cf

Im Anschluss muss jene Datei natürlich noch angelegt und mit dem richtigen Inhalt befüllt werden, wie in folgendem Beispiel:

# Global Directives
checktimeout=10
checkinterval=10
fallback=127.0.0.1:80
autoreload=yes
logfile="/var/log/ldirectord.log"
quiescent=no
#callback="/usr/local/bin/sync_ldirectord"
# Virtual Server for HTTP
virtual=192.168.0.40:80
real=192.168.0.41:80 gate
real=192.168.0.42:80 gate
service=http
request="alive.html"
receive="foobar3000"
scheduler=rr
# persistent=600
protocol=tcp
checktype=negotiate

Die Config ist an und für sich recht einfach zu verstehen. Ein paar Einträge möchte ich jedoch erklären:
callback: Hier kann ein Script angegeben werden, welches nach einem Autoreload ausgeführt wird. Üblicherweise sollte hier eine Synchronisation zu einem zweiten Load Balancer statt finden.
virtual: Die IP samt Port für den Service, der balanced werden soll. Diese IP ist von außen direkt ansprechbar (einfach gesagt: Die IP kommt in den A-Record 😉 ) und muss auf dem Load Balancer als zusätzliche IP konfiguriert werden. Dahinter stehen die Realserver, auf die Anfragen verteilt werden.
checktype: Art der Überprüfung, ob ein Realserver ordnungsgemäß funktioniert. Bei einem Webdienst ist negotiate anzuraten, da hierbei ein Ergebnis (receive) angegeben werden kann, welches bei der Anforderung (request) zurückgegeben werden muss.
scheduler: Die Art, wie verteilt wird. Hier wird nur die Abkürzung eingetragen. Welche Arten es gibt, kann in der Man-Page von ipvsadm nachgelesen werden (Schalter -s, –scheduler)
fallback: Der Name ist selbsterklärend 😉 Sollten Alle Realserver aus dem Pool rausspringen, so wird ein Fallback Server (in unserem Beispiel localhost) eingesetzt. Hier kann beispielsweise eine Wartungsseite ausgeliefert werden.
Nachdem nun auch die Service-IP auf dem Load Balancer-Pi eingerichtet wurde (ifconfig eth0:1 192.168.0.40/32 – in unserem Beispiel), kann der Ldirectord gestartet werden. Im definierten Logfile werden wir jedoch feststellen, dass der Ldirector seine Realserver noch nicht erreichen kann und somit auf den Fallback Server geschaltet hat.

Konfiguration App-Server

Unsere Realserver können leider nicht ohne Weiteres die Anfragen, die vom Load Balancer kommen verarbeiten. Immerhin wird ja die Anfrage direkt an die IP 192.168.0.40 gestellt, welche ja auf den Systemen nicht bekannt ist. Damit das funktioniert, muss die Service-IP auf den Real-Servern noch als Loopbackdevice gebunden werden, damit sich der Realserver auch angesprochen fühlt. Jedoch Vorsicht: Nicht einfach so die Service IP als Loopback einbinden! Das würde dazu führen, dass der Realserver ARP-Anfragen mit seiner MAC-Adresse beantwortet, was wir ja nicht wollen. Das könnte den gesamten Dienst still legen. Hier muss im Vorfeld noch folgendes in die /etc/sysctl.conf eingetragen und mit sysctl -p übernommen werden, was das Verhalten unterbindet:

net.ipv4.conf.all.arp_ignore = 0
net.ipv4.conf.default.arp_ignore = 0
net.ipv4.conf.eth0.arp_ignore = 1
net.ipv4.conf.lo.arp_ignore = 0
net.ipv4.conf.all.arp_announce = 0
net.ipv4.conf.default.arp_announce = 0
net.ipv4.conf.eth0.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 0

Nun kann das Loopbackdevice hochgefahren werden:

root@rpi1:~# ifconfig lo:1 192.168.0.40/32

Sobald nun der Realserver die Datei „alive.html“ mit dem Inhalt „foobar3000“ ausliefern kann, wird er auch im Load Balancer als aktiv markiert und die Anfragen werden entsprechend weitergeleitet. Das der Webdienst richtig dafür eingerichtet wurde, setze ich an der Stelle einfach mal voraus 😉
Das Schöne am Ldirectord ist, dass er sich nicht nur auf Webdienste beschränkt. Es kann jeder TCP/UDP Dienst über den Load Balancer verteilt werden. Durch die optional einstellbare Persistenz kann auch sichergestellt werden, dass eine Verbindung immer wieder bei dem gleichen Realserver ankommen wird (für den konfigurierten Zeitraum).