Archive

Archive for the ‘Linux’ Category

NFSv4 ID Map per DNS

December 14th, 2011
Comments Off

Die praktischsten Features werden in Dokumentationen am tiefsten vergraben. So auch hier: die Konfiguration von NFSv4 kann mit einer Prise DNS stark vereinfacht werden.

In einem TXT-Record kann über das Keyword _nfsv4idmapdomain die Domain der Zone angegeben werden.

_nfsv4idmapdomain 300 IN TXT "example.org"

Steht die obige Zeile innerhalb der Zone example.org, so können die Maschinen die selbst innerhalb von example.org stehen über ihre searchdomain die NFSv4 Domain erfragen.

% dig -t TXT _nfsv4idmapdomain.example.org +short
"example.org"

Der gleiche Eintrag kann natürlich auch in anderen Zonen stehen:

% dig -t TXT _nfsv4idmapdomain.example.com +short
"example.org"

, ,

Ubuntu Linux on ZFS

March 22nd, 2011
Comments Off

There’s an excellent article about installting Ubuntu on ZFS.

,

Hochverfügbarkeit mit Linux – Teil 7.1

March 9th, 2011

Teil 7.1 wird eine Ausnahme der Reihe, denn dieser Artikel befasst sich mit der Thematik aus Teil 7, jedoch auf Red Hat/CentOS basierten Systemen.

Die Konfiguration ist hier mehstufig, zunächst wird der “bond” selbst konfiguriert; wichtig ist nur, daß diese Konfiguration vor allen anderen Netzwerk-Optionen steht.
/etc/modprobe.conf:

1
2
alias bond0 bonding
options bond0 mode=X miimon=100

Der Mode wird hier als Zahl definiert: mode=X.

Mögliche Modi für den “bond” sind:

  • balance-rr – ein Round Robin über die NICs, mode=0
  • active-backup – active/standby-Setup, mode=1
  • balance-xor – die MAC-Adresse des Ziels wird gehashed und entsprechend ein Interface für die Kommunikation ausgewählt. Damit ist grundlegend ein Load Balancing auf Netzwerk-Ebene realisiert, genauso wie eine ausreichende Fehlertolleranz, mode=2
  • broadcast – jedes Paket wird auf allen Interfaces gesendet. Damit entsteht 100%ige Fehlertolleranz, mode=3
  • 802.3addynamic link aggregation per IEEE 802.3ad – erfordert jedoch spezielle Switch-Konfiguration, mode=4
  • balance-tlb – der Host entscheidet je nach Last welche NIC genutzt werden soll, mode=5

Das Interface bond0 muß noch konfiguriert werden:
/etc/sysconfig/network-scripts/ifcfg-bond0:

1
2
3
4
5
6
7
DEVICE=bond0
BOOTPROTO=none
ONBOOT=yes
NETWORK=198.18.0.0
NETMASK=255.255.255.0
IPADDR=198.18.0.1
USERCTL=no

Jede reelle NIC die dem “bond” angehören soll, muß noch entsprechend konfiguriert werden:
/etc/sysconfig/network-scripts/ifcfg-ethX:

1
2
3
4
5
6
DEVICE=ethX
BOOTPROTO=none
ONBOOT=yes
MASTER=bond0
SLAVE=yes
USERCTL=no

Zurück zur Übersicht.

,

Hochverfügbarkeit mit Linux – Teil 7

March 8th, 2011
Comments Off

Mit Heartbeat und Load Balancing kann der Ausfall kompletter Maschinen abgefangen werden, was noch fehlt ist die Redundanz auf Netzwerk-Ebene. Linux kann mehrere Ethernet Interfaces zu einem sogenannten “bond” verknuepfen, und so diese notwendige Redundanz schaffen. Bei Ausfall einer Switch-Verbindung, eines LAN-Kabels oder einer NIC fällt das System nicht auf die Nase, sondern arbeitet mit potentiell verbinderten Ressourcen weiter.

Auf Debian wird zunächst das Paket ifenslave-2.6 benötigt.
Die Datei /etc/network/interfaces wird anschließend um die Konfiguration für den “bond” erweitert:

/etc/network/interfaces:

1
2
3
4
5
6
7
iface bond0 inet static
  address 198.18.0.1
  netmask 255.255.255.0
  network 198.18.0.0
  gateway 198.18.0.254
  slaves eth0 eth1
  bond_mode active-backup

In diesem Beispiel werden eth0 und eth1 zu einem Interface (= bond0) gebündelt. bond_mode active-backup definiert hierbei, daß ein Link als Backup für den anderen konfiguriert werden soll.

Andere mögliche Modi sind:

  • balance-rr – ein Round Robin über die NICs
  • balance-xor – die MAC-Adresse des Ziels wird gehashed und entsprechend ein Interface für die Kommunikation ausgewählt. Damit ist grundlegend ein Load Balancing auf Netzwerk-Ebene realisiert, genauso wie eine ausreichende Fehlertolleranz.
  • broadcast – jedes Paket wird auf allen Interfaces gesendet. Damit entsteht 100%ige Fehlertolleranz.
  • 802.3addynamic link aggregation per IEEE 802.3ad – erfordert jedoch spezielle Switch-Konfiguration.
  • balance-tlb – der Host entscheidet je nach Last welche NIC genutzt werden soll.

Zurück zur Übersicht.

,

Hochverfügbarkeit mit Linux – Teil 6

March 7th, 2011
Comments Off

Nach Teil 5, dem Load Balancing per NAT, geht’s heute um Load Balancing per direct routing.
Zur Erinnerung:

Die Anfragen kommen am Load Balancer an, der die Ziel MAC-Adresse in den Paketen abändert. Sehen wir uns diesen Prozess im Detail an:

  1. Eine Anfrage kommt beim Load Balancer auf Port 80 an, da er auf seinem Interface die angefragte IP-Adresse gebunden hat.
  2. Der Load Balancer ändert das Paket ab, in dem er die MAC-Adresse eines der Web-Server als Ziel einträgt. Anschließend kommt das geänderte Paket wieder auf das Ethernet.
  3. Einer der Web-Server erhält das Paket auf z.B. eth0, jedoch mit einer IP die auf einem dummy-Interface gebunden ist, tut was ein Web-Server eben tut und schickt die Antwort an an den Client zurück. Das Paket erhält als Absender-IP die auf dummy gebundene IP.
  4. Je nach Konfiguration (persistent=) behält der Load Balancer die Information auf welchen Web-Server er den Client geschickt hat eine Weile bei oder entfernt diesen Eintrag aus der Adress-Tabelle.

Notwendig für die Funktion dieses Workflows ist, daß alle Maschinen sich im gleichen Layer 2 Segment befinden. Zwischen dem Load Balancer und den Web-Servern darf bei direct routing kein Router stehen.

Konkret mit IPv4 Adressen bestückt, sieht die Konfiguration auf dem Load Balancer folgendermaßen aus:

Die IP 198.18.0.1 muß direkt auf z.B. eth0 gebunden werden. Dies ist wichtig, damit der Router eine valide MAC-Adresse für 198.18.0.1 lernen kann und die Pakete auf den Load Balancer zustellen kann.

/etc/ha.d/conf/ldirectord.cf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
checktimeout=10
checkinterval=2
autoreload=yes
callback="/etc/ha.d/config_sync.sh"
logfile="local0"
quiescent=yes
 
virtual=198.18.0.1:80
        real=198.18.0.11:80 gate
        real=198.18.0.12:80 gate
        real=198.18.0.13:80 gate
	fallback=127.0.0.1:80
	service=http
	request="lb-test.html"
	receive="shiny captain"
	scheduler=wrr
	protocol=tcp
	checktype=negotiate

Bisher ist die Konfiguration in /etc/ha.d/conf/ldirectord.cf von den IP-Adressen und gate anstatt masq stark identisch, allerdings muß für direct routing auch jeder einzelne Web-Server angefasst werden.

Zunächst muß das dummy-Modul geladen werden, so daß dem System das Interface dummy0 zur Verfügung steht.
root@webserver:~# modprobe dummy
root@webserver:~# echo dummy >> /etc/modules

Die Datei /etc/network/interfaces wird um die Konfiguration für dummy0 erweitert:

1
2
3
4
auto dummy0
iface dummy0 inet static
        address 198.18.0.1
        netmask 255.255.255.255

Ein beherztes ifup dummy0, und alles ist bereit für einen ersten Test. Für diesen Test kann der ldirectord von Hand gestartet werden, also per /etc/init.d/ldirectord start, allerdings sollte später die /etc/ha.d/haresources um die entsprechende Zeile erweitert werden. Wenn alles klappt, sollte ipvsadm -Ln nach wenigen Sekunden die ersten Ausgaben liefern:

root@frasier:~# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 198.18.0.1:80 wrr persistent 1200
-> 198.18.0.11:80 Route 1 0 0

Der Load Balancer hat erkannt, daß auf 198.18.0.11 der konfigurierte Service erreichbar ist, sofern bei Weight eine “1″ steht. Bei “0″ konnte keine Verbindung aufgebaut werden, und quiescent=yes ist gesetzt. (Siehe Teil 5)

root@frasier:~# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 198.18.0.1:80 wrr persistent 1200
-> 198.18.0.11:80 Route 0 0 0

Entsprechendes mit IPv6 ist auch kein Hexenwerk.

In der Datei /etc/ha.d/conf/ldirectord.cf auf checktype und checkcommand achten, und die IPv6 Adressen ausschreiben und nicht mit :: abkürzen.
/etc/ha.d/conf/ldirectord.cf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
checktimeout=10
checkinterval=2
autoreload=yes
callback="/etc/ha.d/config_sync.sh"
logfile="local0"
quiescent=no
 
virtual=[2001:db8:0:1:0:0:0:a]:443
        real=[2001:db8:0:1:0:0:0:1]:443 gate
        real=[2001:db8:0:1:0:0:0:2]:443 gate
        real=[2001:db8:0:1:0:0:0:3]:443 gate
	fallback=[::1]:443
        persistent=1200
	scheduler=wrr
	protocol=tcp
	checktype=external
        checkcommand="/usr/share/nagios/libexec/check_http"

Entsprechend der Konfiguration für IPv4 muß auch die IP-Adresse 2001:db8:0:1::a auf jedem einzelnen Web-Server gebunden werden.

1
2
3
4
auto dummy0
iface dummy0 inet6 static
        address 2001:db8:0:1::a
        netmask 64

Mit ipvsadm -Ln werden auch IPv6 Verbindungen angezeigt.
root@frasier:~# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 198.18.0.1:80 wrr persistent 1200
-> 198.18.0.11:80 Route 1 0 0
-> 198.18.0.12:80 Route 1 0 0
-> 198.18.0.13:80 Route 1 0 0
TCP [2001:db8:0:1::a]:80 wrr persistent 1200
-> [2001:db8:0:1::1]:80 Route 1 0 0
-> [2001:db8:0:1::2]:80 Route 1 0 0
-> [2001:db8:0:1::3]:80 Route 1 0 0

Zurück zur Übersicht.

, , , ,

802.1q mit Debian

March 5th, 2011
Comments Off

Nach dem Ausschnitt aus der haresources in Teil 1 der Hochverfügbarkeits-Reihe bin ich angesprochen worden, was es denn mit dem Interface eth2.82 (Zeile 3) und eth2.103 (Zeile 4) auf sich hat.

1
2
3
4
frasier IPaddr2::198.18.0.1/32/eth0 \
        IPaddr2::198.19.0.1/32/eth1 \
        IPaddr2::10.111.222.1/32/eth2.82 \
        IPv6addr::2001:db8:0:0:0:0:0:1/128/eth2.103

Es handelt sich dabei um nach IEEE 802.1q getaggte VLAN Interfaces. eth2.82 bedeutet nichts anderes als das VLAN 82 auf eth2. Es wird allerdings ein zusätzliches Modul im Kernel benötigt, namentlich 8021q (echo 8021q >> /etc/modules).

Wie baut man sowas?
Für obiges Beispiel: (in /etc/network/interfaces)

1
2
3
4
5
6
7
auto eth2.82
iface eth2.82 inet static
        address 10.111.222.1
        network 10.111.222.0
        netmask 255.255.255.0
        broadcast 10.111.222.255
        vlan_raw_device eth2

Die Gegenstelle, z.B. ein Cisco Switch sieht dann für das Beispiel so aus:

1
2
3
4
5
6
7
8
9
!
interface FastEthernet0/4
 switchport trunk encapsulation dot1q
 switchport trunk allowed vlan 1,82,103
 switchport mode trunk
!
interface VLAN82
 ip address 10.111.222.241 255.255.255.0
!

Keine schwarze Magie™.

Hochverfügbarkeit mit Linux – Teil 5

March 4th, 2011

In Teil 2 habe in angefangen über den ldirectord zu schreiben. Nochmal zur Erinnerung: der ldirectord ist ein User-Space Script, welches mit Hilfe des IP Virtual Servers (kurz IPVS) im Kernel einen Load Balancer in Software abbildet. Angerissen habe ich bereits zwei Methoden zum Load Balancing,

  • NAT
  • direct routing

Dieser Artikel beschäftigt sich mit Load Balancing per NAT.

Nochmal zum Konzept:

Die Anfragen kommen am Load Balancer an, der anschließend auf die Web-Farm NATet. Sehen wir uns diesen Prozess im Detail an:

  1. Eine Anfrage kommt beim Load Balancer auf dem externen Interface Port 80 an
  2. Der Load Balancer verzeichnet Verbindungsdaten wie
    • Quell-IP
    • Ziel-IP
    • Quell-Port
    • Ziel-Port
    • Zeitstempel der Verbindung

    und ändert das Paket an Hand seiner Konfiguration ab. Die Ziel-IP wird durch eine der Web-Server IPs im internen Netz ausgetauscht und mit der entsprechenden MAC-Adresse versehen. Danach schickt der Load Balancer das Paket auf dem internen Interface wieder auf’s Ethernet.

  3. Einer der Web-Server erhält das Paket, tut was ein Web-Server eben tut und schickt die Antwort an sein default-Gateway (den Load Balancer) zurück.
  4. Der Load Balancer erhält das Paket vom Web-Server und ändert die Quell-IP wieder auf seine eigene IP zurück, so daß für den anfragenden Client die Verbindung die er zum Load Balancer aufgebaut hat konsistent bleibt.
  5. Je nach Konfiguration (persistent=) behält der Load Balancer die Information auf welchen Web-Server er den Client geschickt hat eine Weile bei oder entfernt diesen Eintrag aus der Adress-Tabelle.

Abgesehen von der Entscheidung auf welchen Ziel Web-Server die Verbindung geNATtet wird, unterscheidet sich dieser Prozess nicht vom NAT in z.B. einer Fritz!Box. Zum besseren Verständnis der Konfiguration, obiges Beispiel mit IPv4 Adressen:

Das externe Interface des Load Balancers steht in 198.18.0.0/24 und das interne Netz mit der Web-Farm wird durch 10.0.0.0/24 repräsentiert. Durch dieses Setup lassen sich effizient öffentliche IPv4-Adressen einsparen, denn für die Website www.example.org wird trotz mehrerer Web-Server nur eine einzige IPv4 Adresse benötigt.
Die Konfiguration des ldirectord geschieht in der Datei /etc/ha.d/conf/ldirectord.cf, wobei der Pfad zu dieser Datei in /etc/default/ldirectord überschrieben werden kann, z.B. wenn man den ldirectord nicht mit Heartbeat kombinieren möchte.

/etc/ha.d/conf/ldirectord.cf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
checktimeout=10
checkinterval=2
autoreload=yes
callback="/etc/ha.d/config_sync.sh"
logfile="local0"
quiescent=yes
 
virtual=198.18.0.1:80
        real=10.0.0.21:80 masq
        real=10.0.0.22:80 masq
        real=10.0.0.23:80 masq
	fallback=127.0.0.1:80
	service=http
	request="lb-test.html"
	receive="shiny captain"
	scheduler=wrr
	protocol=tcp
	checktype=negotiate

Die Konfiguration von oben nach unten:

  • checktimeout und checkinterval definieren wie häufig die Ziel-Maschinen geprüft werden sollen, bzw. wie hoch das Timeout definiert werden soll, bis ein Server als tot definiert wird. Die Angaben sind in Sekunden.
  • autoreload=yes definiert, daß die Konfiguration neu geladen wurde, sobald sie sich auf der Festplatte geändert hat. Damit einher geht
  • callback, denn hier kann ein Binary oder Script angegeben werden, das ausgeführt wird, sobald die Konfiguration sich geändert hatte. config_sync.sh ist nur ein Beispiel, dieses Script ist nicht Teil der Distribution.
  • logfile definiert eine Log-Datei bzw. eine Syslog Facility
  • auf quiescent=yes werde ich weiter unten noch genauer eingehen, denn dieser Punkt arbeitet eng mit persistent in der virtual-Sektion zusammen.

Die virtual-Sektion definiert jeweils eine “virtuelle” IP (das, was man in den DNS für www einträgt) und kann mehrfach in der Konfiguration stehen, sofern mehr als nur eine IP gebalanced werden soll. Jede Zeile der Konfiguration die zu einer virtual-Sektion gehört muß mit einem Tabulator (\t) eingerückt werden; leider ist die Syntax-Prüfung etwas seltsam und man bekommt extrem nichts sagende Fehlermeldungen.

  • virtual=198.18.0.1:80 definiert 198.18.0.1 mit Port 80 als virtuelle Adresse. Diese IP muß auf dem Load Balancer lokal (z.B. an eth0, nicht an lo oder dummy0) gebunden werden, denn ldirectord bindet die IP nicht automatisch. Bei einem HA-Setup empfiehlt es sich natürlich diese IP als Cluster-Ressource zu definieren.
  • real=10.0.0.21:80 masq definiert einen Backend-Server inklusive des Ports. Es ist durchaus möglich intern die Web-Server auf anderen Ports zu betreiben, nach außen allerdings weiter auf Port 80 verfügbar zu sein. masq schaltet den IPVS in den NAT-Modus.
  • Mit fallback=127.0.0.1:80 wird ein Notfall-Server definiert, der dann genutzt wird, wenn alle reellen Server als defekt definiert wurden. Hier kann z.B. ein “Wartungsarbeiten, komm später wieder” Text auf einem lokalen Web-Server definiert werden; oder man läßt die Zeile komplett weg, wenn man keinen Fallback-Server hat oder möchte. Anfragen gehen dann allerdings ins Leere.
  • service definiert den zu balancenden Dienst, sofern checktype=negotiate gesetzt ist. Eine Liste der verfügbaren Dienste befindet sich in der man-page des ldirectord, interessant sind zwei besondere Fälle:
    • none: es soll keine Form von Checks stattfinden. Wenn ein Server ausfällt wird der Load Balancer das nicht bemerken und den Server weiterhin in der Verteilung nutzen.
    • simpletcp: ein generischer Service der mit request eine TCP-Verbindung aufbaut und das empfangene Ergebnis mit receive matcht.

    Für “standard” Services wie http, https oder ssh enthält der ldirectord sehr brauchbare Checks, die die Verfügbarkeit des Services exzellent prüfen.

  • scheduler definiert die Load Balancing Methode, den Scheduler Algorithmus. Zur Verfügung stehen 10 verschiedene Algorithmen, unter anderem
    • rrRound Robin: verteile alle Anfragen der Reihe nach auf die Server
    • wrrWeighted Round Robin, gewichteter Round Robin: arbeitet wieder ungewichtete Round Robin, man kann den Servern aber verschieden hohe Prioritäten geben, um beispielsweise ungleich starke Hardware besser ausnutzen zu können
    • lcLeast-Connection: Maschinen mit weniger offenen Verbindungen als andere bekommen bevorzugt neue Verbindungen zugeteilt
    • wlcWeighted Least-Connection: ebenfalls vergleichbar mit Least-Connection, allerdings wieder mit Gewichtung der Maschinen
    • dhDestination Hashing: erstellt einen Hash über die Ziel-IP und weist darüber einen Backend-Server zu
    • shSource Hashing: erstellt einen Hash über die Quell-IP und weist darüber einen Backend-Server zu
      IPVS kennt weiterhin noch Locality-Based Least-Connection (mit und ohne Replikation) sowie Shortest Expected Delay und Never Queue, aber diese Scheduling Alorithmen habe ich noch nie in freier Wildbahn gesehen und vernachlässige sie daher an dieser Stelle. Die man-Page von ipvsadm gibt im Detail Auskunft.
  • Schließlich gibt checktype noch an auf welche Weise die Backend-Server geprüft werden sollen. Mehr dazu gleich mehr.

Mit IPv6 ist die Konfiguration nahezu identisch, abgesehen von den Check-Methoden.

Außerdem wird diesmal https gebalanced.
/etc/ha.d/conf/ldirectord.cf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
checktimeout=10
checkinterval=2
autoreload=yes
callback="/etc/ha.d/config_sync.sh"
logfile="local0"
quiescent=no
 
virtual=[2001:db8:0:1:0:0:0:1]:443
        real=[2001:db8:0:2:0:0:0:21]:443 masq
        real=[2001:db8:0:2:0:0:0:22]:443 masq
        real=[2001:db8:0:2:0:0:0:23]:443 masq
	fallback=[::1]:443
        persistent=1200
	service=http
	request="lb-test.html"
	receive="shiny captain"
	scheduler=wrr
	protocol=tcp
	checktype=negotiate

Zwei Konfigurations-Direktiven bin ich Euch noch schuldig: quiescent und checktype.
Um zu erkennen in welchem Zustand sich die Backend-Server befinden, muß der Load Balancer regelmäßig prüfen, ob die Maschinen wie gewünscht antworten und ihren zugewiesenen Dienst erfüllen können. Wird checktype=connect gesetzt, so baut der ldirectord eine einfache TCP-Verbindung auf und prüft ob ein erwarteter String zurück gemeldet wird. Bei UDP würde es hier schon etwas schwerer werden, und bei Protokollen wie https muß sogar ein SSL-Handshake stattfinden. Mit einem TCP-Connect ist es also in manchen Fällen nicht unbedingt getan, hier wird etwas mehr Logik notwendig. checktype=negotiate in Verbindung mit service=https, um beim IPv6 Beispiel zu bleiben baut eine Verbindung auf Port 443 zu den Backend-Servern auf, macht den erwarteten SSL-Handshare und wertet dann den mit receive angegebenen String aus. Wird request und receive nicht angegeben, so gilt der Server bereits bei korrektem Verbindungsaufbau als intakt, ob aber beispielsweise Datenbank-Verbindungen funktionieren oder nicht wird der Load Balancer nicht erkennen. Hier ist Kreativität gefragt eine “OK“- bzw. “ERROR“-Seite zu basteln, die alle notwendigen Verbindungen der Web-Applikation prüft und entsprechend einen Status abliefert. Sofern notwendig, kann checktimeout nach oben hin angepasst werden, wenn z.B. alle Datenbank-Verbindungen aufzubauen länger als 10 Sekunden dauert.
Wird ein Backend-System auf Grund der Checks als defekt markiert, kommt quiescent ins Spiel. Bei yes wird der betroffene Backend-Server still gelegt, es werden also keine neuen Verbindungen zugelassen, er befindet sich aber noch in der Kernel-Tabelle des IPVS. Wird quiescent=no gesetzt, so wird er restlos aus der Kernel-Tabelle entfernt. In das IPv6/SSL Beispiel habe ich noch den Parameter persistent=1200 geschmuggelt. persistent definiert wie lange .. genau, das stand ja weiter oben schon, wie lange eine Verbindung in der Kernel-Tabelle gehalten werden soll, wieviele Sekunden also ein Client auf den gleichen Backend-Server gebalanced werden soll. Bei quiescent=no wird bei Ausfall eines Servers die Verbindung trotz persistent direkt neu verteilt, bei quiescent=yes muß erst das Timeout von hier 1200 Sekunden (= 20 Minuten) abgewartet werden.

Bleibt nur noch der erwähnte Sonderfall mit den Check-Methoden im Zusammenhang mit IPv6: checktype=negotiate funktioniert mit den meisten Protokollen für IPv6 noch nicht. (Stand März 2011, ldirectord-Version v1.186-ha aus Debian Squeeze) Dies ist allerdinge kein Show-Stopper, denn checktype kennt noch einen weiteren Parameter: external.

1
2
3
4
5
6
7
8
virtual=[2001:db8:0:1:0:0:0:1]:80
        real=[2001:db8:0:2:0:0:0:21]:80 masq
        real=[2001:db8:0:2:0:0:0:22]:80 masq
        real=[2001:db8:0:2:0:0:0:23]:80 masq
	fallback=[::1]:80
	scheduler=rr
	checktype=external
        checkcommand="/usr/share/nagios/libexec/check_http"

Bei checktype=external kann mit checkcommand ein beiliebiges Binary oder Script angegeben werden, welches den Backend-Server prüft. Nagios-Plugins, /bin/true oder was dem geneigten Admin sonst noch so einfällt, wichtig ist nur, daß entsprechende Error-Codes an den ldirectord geliefert werden. Und der Gedanke bei Ausfall eines real-Servers gleich einen passive service check an Nagios weiter zu geben hat doch was, oder? ;-)

Teil 6 beschreibt direct routing im Detail.

Zurück zur Übersicht.

, , , ,

Hochverfügbarkeit mit Linux – Teil 4 – Heartbeat per Puppet

March 3rd, 2011

Das Fazit des ersten Artikes: einen Heartbeat-Cluster zu bauen ist nicht sonderlich schwer, eigentlich nur Fleißarbeit. Und diese Fleißarbeit zu automatisieren ist “die hohe Kunst” der Faulheit. ;-) Puppet hilft dabei zu automatisieren.

Um das Heartbeat-Modul nutzen zu können wird zunächst noch die Modul-Sammlung aus dem folgenden Repository benötigt:
git clone git://github.com/ripienaar/puppet-concat.git
Dann noch das eigentlich Heartbeat-Modul:
git clone git://github.com/shl/ipvs-lb.git

In den node-Definitionen der Cluster-Nodes muß das Modul noch eingebunden und damit konfiguriert werden:

1
2
3
4
5
6
heartbeat { 'ClusterName':
  resources = [ '198.18.23.42', 'nfs-kernel-server' ],
  key = 'banane', 
  iface = 'eth0',
  peer_ip = '198.19.0.1' 
}

Puppet generiert nun beim nächsten run die notwendigen Konfigurationen und baut damit den HA-Cluster. Und weil man damit massig Zeit sparen kann, darf dieser Artikel auch etwas kürzer sein.

Zurück zur Übersicht.

, ,

Hochverfügbarkeit mit Linux – Teil 3 – DRBD

March 2nd, 2011
Comments Off

Der in Teil 1 aufgebauten Heartbeat-Cluster soll nun ein Aufgabe bekommen: hochverfügbarer NFS-Server mit lokalem Storage. Was sind die wichtigen Parameter dabei?

  1. eine gemeinsame Cluster-IP unter der die Clients die NFS-Shares mounten können
  2. das zu exportierende Dateisystem muß auf beiden Nodes lokal vorhanden sein
  3. das zu exportierende Dateisystem muß konstant zwischen den Nodes gespiegelt werden
  4. bei Ausfall eines Nodes muß der andere Node in der Lage sein das Dateisystem wie erwartet per NFS zu exportieren

Hier beitet sich DRBD an, Distributed Replicated Block Device, eine Technologie zur synchronen Replikation von Block Devices über das IP-Netzwerk. Pro Blech wird ein physikalisches Volume (eine Festplatte, eine RAID-Gruppe, ein USB-Stick oder sonstwas…) definiert, welches von DRBD verwaltet und synchronisiert wird. Im User-Space taucht ein neues Device auf, z.B. /dev/drbd0 und kann auf dem aktiven Node wie ein normales Device verwendet werden. Auf dem passiven Node ist das Device nicht mountbar, so lange bis mittels Heartbeat definiert wird, daß dieser Node das Dateisystem exklusiv mounten darf.

Wie funktioniert diese Replikation?
Simpel ausgedrückt: jeder Schreib-Zugriff auf das DRBD-Device macht den Umweg über den IP-Stack und damit auf den anderen Node. Jedes Bit wird also zweimal geschrieben, und erst wenn beide Maschinen die Daten korrekt auf die Platten geschoben haben, bekommt der User das entsprechende Feedback und der Schreibvorgang wird beendet.

Setup:
Auf beiden Nodes benötigen wir zwei neue Partitionen, eine für die Nutz-Daten und eine weitere für die DRBD Meta-Daten. Die Meta-Partition muß minimal 128MB groß sein, je nach Größe der Daten-Partition auch gerne größer. An “Frasier” und “Niles” habe ich der Einfachheit halber je einen USB-Stick angeschlossen und zwei Partitionen erstellt:

  • /dev/sdb1 mit 512MB für die Nutz-Daten
  • /dev/sdb2 mit 256MB für die Meta-Daten

Folgendes ist auf beiden Nodes auszuführen:
root@frasier:~# apt-get install drbd8-utils
root@frasier:~# modprobe drbd
root@frasier:~# echo drbd >> /etc/modules

Die Konfiguration von DRBD wird in /etc/drbd.conf und /etc/drbd.d/* erledigt, wobei /etc/drbd.conf nur zwei include-Statements für /etc/drbd.d/* enthält und nicht weiter angepasst werden muß. Interessanter ist die Datei /etc/drbd.d/global_common.conf, wobei auch hier keine für das Beispiel notwendigen Änderungen vorzunehmen sind.
Für jede Ressource, die von DRBD verwaltet werden soll, wird eine spezielle Konfigurationsdatei in /etc/drbd.d/ angelegt und entsprechend benannt. Wegen dem include in /etc/drbd.conf muß jede Ressourcen-Datei *.res benannt werden.

/etc/drbd.d/r0.res:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
resource r0 {
  protocol C;
  handlers {
    pri-on-incon-degr "echo o > /proc/sysrq-trigger ; halt -f";
    pri-lost-after-sb "echo o > /proc/sysrq-trigger ; halt -f";
    local-io-error "echo o > /proc/sysrq-trigger ; halt -f";
  }
 
  startup {
    degr-wfc-timeout 120;    # 2 minutes.
  }
 
  disk {
    on-io-error detach;
  }
 
  net {
  }
 
  syncer {
    rate 1M; 
    al-extents 257;
  }
 
on frasier {
    device /dev/drbd0;
    disk /dev/sdb1;
    address 198.18.1.10:7788;
    meta-disk /dev/sdb2[0];
  }
 
on niles {
    device /dev/drbd0;
    disk /dev/sdb1;
    address 198.18.1.11:7788;
    meta-disk /dev/sdb2[0];
  }
}

Es wird eine Ressource r0 definiert und entsprechend konfiguriert. Die relevanten Teile der Konfiguration von oben nach unten:

1
2
3
4
5
  handlers {
    pri-on-incon-degr "echo o > /proc/sysrq-trigger ; halt -f";
    pri-lost-after-sb "echo o > /proc/sysrq-trigger ; halt -f";
    local-io-error "echo o > /proc/sysrq-trigger ; halt -f";
  }

Was soll passieren, wenn DRBD zu starke I/O-Fehler feststellt? In diesem Beispiel ist die konsistenz der Daten vorrangig, daher schalte den Node ab und schreibe gar nichts mehr. Wer ein anderes Verhalten wünscht tausche die Befehle in den " " entsprechend aus.

1
2
3
4
  syncer {
    rate 1M; 
    al-extents 257;
  }

Mit welcher Geschwindigkeit sollen die Daten zwischen den Nodes synchronisiert werden? Im Falle der USB-Sticks an “Frasier” und “Niles” hier nur mit maximal 1MB/s, doch falls entsprechend schnelle Links vorhanden sind (z.B. ein dedizierter Gigabit- oder 10-Gigabit-Link) wird hier ein Wert in Megabyte pro Sekunde angegeben.

1
2
3
4
5
6
on frasier {
    device /dev/drbd0;
    disk /dev/sdb1;
    address 198.18.1.10:7788;
    meta-disk /dev/sdb2[0];
  }

Einen solchen Block gibt es pro Node einmal, hier werden die Devices und die IP-Adresse/DNS-Name des Nodes definiert. Wie oben beschrieben ist /dev/sdb1 die Partition für die Nutz-Daten und /dev/sdb2 für die Meta-Daten des DRBD reserviert.

Die Konfigurationen müssen auf allen Nodes identisch sein. Es bietet sich also an z.B. mit rsync das komplette /etc/drbd.d/ zu übertragen. Jetzt wird es Zeit das DRBD-Device zu initialisieren:

root@frasier:~# drbdadm create-md r0
root@niles:~# drbdadm create-md r0
root@frasier:~# drbdadm up all
root@niles:~# drbdadm up all
root@frasier:~# drbdsetup /dev/drbd0 primary -o
root@frasier:~# mkfs.ext3 /dev/drbd0
root@frasier:~# mkdir /data
root@niles:~# mkdir /data
root@frasier:~# mount -t ext3 /dev/drbd0 /data

Im Hintergrund hat das DRBD schon begonnen die Devices zu synchronisieren, was man mit cat /proc/drbd beobachten kann. Sobald der initiale Transfer abgeschlossen ist, wird es Zeit den zugehörigen Service zu starten. Damit ist die Konfiguration von DRBD beendet und es fehlt nur noch die Anpassung des Heartbeats.

root@frasier:~# /etc/init.d/drbd start
root@niles:~# /etc/init.d/drbd start

Sowohl die DRBD Ressource r0 als auch das Filesystem werden als Cluster-Ressource in der Datei /etc/ha.d/haresources auf beiden Nodes verankert.

/etc/ha.d/haresources:

1
2
3
4
frasier IPaddr2::198.18.0.1/32/eth0 \
        drbddisk::r0 \
        Filesystem::/dev/drbd0::/data::ext3 \
        nfs-kernel-server

Auf “frasier” ist /data bereits gemountet, der NFS-Server wird mit entsprechenden Einträgen in /etc/exports direkt loslegen können. Auf “niles” läuft kein NFS-Server und /data ist ein leerer Mountpoint. Sobald “frasier” zur Wartung abgeschaltet wird oder ausfällt, wird Heartbeat auf “niles” erst das Dateisystem mounten und anschließend den NFS-Server starten. Richtig geraten, die Reihenfolge in /etc/ha.d/haresources spielt eine Rolle. :-)

Zurück zur Übersicht.

, , ,

Hochverfügbarkeit mit Linux – Teil 2

March 1st, 2011
Comments Off

Der Begriff Cluster wird häufig in unterschiedlichen Zusammenhängen genutzt und ist daher leider im allgemeinem Sprachgebrauch etwas verwaschen. Von HPC-Clustern oder partitionierten Datenbanken abgesehen, sind folgende zwei Cluster-Typen in dieser Artikel-Reihe interessant:

  • HA-Cluster
    Mit einem High Availability-Cluster ist der Zusammenschluß von zwei oder mehr Maschinen gemeint, der sicherstellt, daß ein Dienst auch bei Ausfall eines Nodes verfügbar ist. Grundsätzlich gibt es verschiedene Modelle einen solchen HA-Cluster zu designen, doch bisher sind mir in der Praxis bei einem HA-Dienst nur active/passive Cluster und bei mehreren Diensten active/active Cluster begegnet.
  • Load Balancing Cluster
    Typisches Einsatzgebiet eines Load Balancing Clusters sind Web-Farmen. Die Web-Farm besteht aus mehreren Web-Servern mit identischem Inhalt, und ein (hoffentlich) redundanter Load Balancer stellt sicher, daß die Anfragen entsprechend auf die Web-Server verteilt werden.

Zur Verdeutlichung:
Ein active/passive HA-Cluster mit verschiedenen Cluster-Ressourcen, die immer nur auf dem aktiven Node ausgeführt werden. Alle weiteren Nodes dienen ausschließlich zu Standby Zwecken.

Ein active/active HA-Cluster, auf dem mehrere Cluster-Ressourcen auf mehreren Nodes ausgeführt werden. Im Ausfall-Moment werden die ausfallenden Ressourcen auf die übrigend Nodes verteilt. (Die Anzahl und Leistungskraft der Nodes sollte entsprechend gewählt werden, daß bei Ausfall oder Wartung eines Nodes die verbleibenden Nodes die Aufgaben erledigen können.)

Dieser Artikel soll sich mit Load Balancing beschäftigen.

Um beim Beispiel der Web-Farm für Load Balancing zu bleiben: Die Aufgabenstellung lautet, ein Balancing über drei Web-Server zu realisieren.

Möglichkeit 1: DNS
Load Balancing per DNS Round Robin. Im DNS wird pro Web-Server ein Eintrag für den entsprechenden DNS-Namen gemacht.

1
2
3
4
5
6
www   IN A    198.18.20.1
www   IN A    198.18.20.2
www   IN A    198.18.20.3
www   IN AAAA 2001:db8::1 
www   IN AAAA 2001:db8::2 
www   IN AAAA 2001:db8::3

Ausfallsicherheit bietet diese Lösung leider keine, denn die DNS-Antwort interessiert sich genau gar nicht für den Zustand der Web-Server. Allerdings führen die Mehrfacheinträge im DNS zu einer gewissen Gleichverteilung der Anfragen. Fazit: machen wir lieber richtiges Load Balancing. ;-)

Möglichkeit 2: Load Balancing per NAT
Mit Hilfe des ldirectord und dem IP Virtual Server im Kernel können wir ein recht zuverlässiges und performantes Load Balancing erreichen. Es wird hierbei zwischen zwei “Klassen” von IP-Adressen unterschieden:

  • virtuellen Adressen
    Diese IPs werden auf dem Load Balancer lokal gebunden und in den DNS für www.example.org eingetragen. Die einzelnen Web-Server kennen diese Adresse nicht.
  • reelle Adressen
    IPs die auf den Web-Servern gebunden sind und für die Kommunikation zum Load Balancer dienen.

Wenn ein Client nun www.example.org aufruft, so wird die Verbindung auf dem Load Balancer terminiert. Der Client wird keine Kommunikation zu den reellen Web-Servern aufbauen. Der Load Balancer allerdings nutzt NAT um die Verbindung auf einen der Web-Server durchzustellen und das entsprechende Antwort-Paket wieder dem Client zuzuordnen.

Leider bringt diese Möglichkeit alle Nachteile die man von NAT kennt mit, bietet allerdings schon deutliche Vorteile gegenüber dem DNS Round-Robin. Ein klarer Vorteil bleibt natürlich: man spart öffentliche IP-Adressen, was bei IPv4 heute ein Argument sein sollte (!).

Um späteren Artikeln etwas vorzugreifen: eine beispielhafte Konfiguration für den ldirectord und Load Balancing per NAT:

1
2
3
4
5
6
7
virtual=198.18.1.100:80
        real=198.18.20.1:80 masq
        real=198.18.20.2:80 masq
        real=198.18.20.3:80 masq
        service=http
        persistent=1200
        checktype=connect

Möglichkeit 3: Load Balancing auf Layer 2
Bei Durchsatz und Verfügbarkeit hat das Load Balancing auf dem ISO/OSI Layer 2 klar gewonnen, allerdings ist das Setup etwas komplizierter. Eine Anfrage die auf der “virtuelle” Adresse eingeht wird vom Load Balancer entgegen genommen und verarbeitet. Die Antwort auf das Paket kommt allerdings vom Web-Server selbst, und zwar direkt an den anfragenden Client.

Die böse Magie™, die der Load Balancer an dieser Stelle treibt geschieht – wie oben bereits geschrieben – auf dem ISO/OSI Layer 2. Das Paket wird vom Balancer in so fern bei der Verarbeitung abgeändert, als das er die MAC-Adresse einer der Web-Server als Ziel-Adresse einträgt und das Paket wieder auf das Ethernet schickt. Die Web-Server sind nun so konfiguriert, daß sie die virtuelle IP auf einem nicht ARP‘enden dummy-Interface konfiguriert haben, so daß der Kernel das Paket mit gutem Gewissen annehmen und verarbeiten kann. Das Antwort-Paket bekommt als Absender die virtuelle IP und wird dem Client direkt zugestellt. Der Client selbst ist nicht in der Lage zu erkennen ob und wenn ja welche Form von Load Balancing involviert war.

Auch hier vorgegriffen: eine beispielhafte Konfiguration für den ldirectord und Load Balancing per direct routing:

1
2
3
4
5
6
7
virtual=198.18.20.10:80
        real=198.18.20.1:80 gate
        real=198.18.20.2:80 gate
        real=198.18.20.3:80 gate
        service=http
        persistent=1200
        checktype=connect

Auf das Thema Load Balancing und die praktische Umsetzung mittels ldirectord werde ich in späteren Artikel noch genauer eingehen.

Zurück zur Übersicht.

, ,