Lizenzkostenfreier Virtualisierungscluster mit CentOS 6.2
Es gibt ein paar Techniken, die habe ich während meiner Zeit in der IT sehr zu schätzen gelernt - besonders solche, die mir das Leben leichter machen. Für diesen Blog-Eintrag relevant sind unter anderem:
- der Pacemaker-Cluster
- libvirt als einheitliche Schnittstelle zu Virtualisierungstechniken
- KVM als zuverlässige und im Kernel integrierte Virtualisierungstechnik
- der Device Mapper im allgemeinen und Multipathing im speziellen
- der Cluster LVM sowie der Cluster Manager CMAN von RedHat
Seit der Version 6 von RHEL (RedHat Enterprise Linux) ist Pacemaker in der Distribution als Tech-Preview enthalten. Und während man auch früher schon über Repositories von Dritten sehr leicht eine Umgebung aus Corosync (also Kommunikationsschicht) und Pacemaker aufbauen konnte, so ist die wirklich große Neuerung in dieser Version die Integration von Pacemaker in den bestehenden CMAN-Stack. Diese Integration ermöglicht es nämlich endlich, Dinge wie geclustertes LVM oder GFS2 zu nutzen (die beide auf den DLM, den “Distributed Lock Manager” angewiesen sind), ohne auch nur ein Stück Zusatzsoftware von dritter Seite aus beschaffen zu müssen. In diesem Eintrag möchte ich mal zeigen, wie einfach es im Prinzip geht, einen Cluster aufzubauen, den man dann z.B. benutzen kann, um unwichtige Systeme zu virtualisieren.
Das Prinzip soll dabei so KISS wie möglich bleiben:
- Jede virtuelle Maschine bekommt einen eindeutigen Namen.
- Jeder Maschine wird als “Systemplatte” mindestens ein eigenes LV zugewiesen (die Maschine brownout05 bekommt das LV
kvm_brownout05
).
Die eine Sache, auf die ich nicht genauer eingehen werde, ist die Einrichtung des Resource Agents “VirtualDomain” - dazu gibt’s Wiki-Dokumentation. Ich will hier wirklich nur über die Einrichtung des Clusters sprechen.
Voraussetzungen
- zwei Server, CentOS 6.2, mit Namen
magma1
undmagma2
, mit jeweils vier Ethernet-Ports und zwei FC-Ports - die vier Ethernet-Ports wurden via Bonding zu zwei redundanten Interfaces kombiniert (
bond0
undbond1
) - die physikalischen Anschlüsse des Interfaces
bond0
sind an zwei verschiedene Switches angeschlossen und dienen der Kommunikation mit dem Rest der Welt - die beiden Maschinen können sich gegenseitig unter den Namen
magma1
undmagma2
anpingen - für KVM/libvirt wurde eine Bridge eingerichtet, die es erlaubt, virtuelle Maschinen in allen Netzwerken einzurichten, die die Maschine bedient (read: 802.1q beachten!)
- die physikalischen Anschlüsse des Interfaces
bond1
sind an zwei miteinander verbundene Switches angeschlossen und dienen als dedizierter(!) Heartbeat-Link - die beiden Maschinen können sich via
bond1
gegenseitig unter den Namenmagma1-hb
undmagma2-hb
anpingen - es steht eine externe Storage mit zwei Fibre-Channel-Controllern mit je zwei Ports zur Verfügung
- die Controller der Storage wurden redundant mit zwei SAN-Switchen verbunden
- die FC-Anschlüsse der Server wurden ebenfalls redundant mit den SAN-Komponenten verbunden
- die
/etc/multipath.conf
ist so eingerichtet, daß mindestens eine LUN auf dem Linux-System verfügbar ist, z.B. als/dev/mpath/msa1_lun1
- die
/etc/lvm.conf
wurde so eingerichtet, daß Volume Groups (VGs) nur auf den Multipath-Devices, nicht den “darunter” liegenden SCSI-Devices gesucht werden
Ein erfahrener Admin dürfte für die Konfiguration dieses Setups (ohne HW-Einbau) wohl kaum länger als einen halben Tag benötigen.
Grundkonfiguration des Clusters:
Der erste Schritt stellt auf beiden Knoten die Installation der benötigten Software dar:
|
|
Der erste Schritt ist das einrichten von CMAN. Als Kommunikationsschicht
verwendet dieser Corosync/TOTEM, und wir wollen hier auch gleich ein
Corosync-Feature verwenden, das die Zuverlässigkeit weiter erhöhen soll: Die
Kommunikation zwischen den beiden Knoten soll zwar primär über den HB-Switch
erfolgen, wenn dieser jedoch wegfällt ist das Ziel, einen redundanten
Kommunikationsring zu etablieren, der die Netzwerkstrecke benutzt, über die die
beiden Maschinen auch mit der Aussenwelt kommunizieren. Und ferner wollen wir
sicher gehen, daß CMAN auch startet, wenn kein Quorum vorhanden ist - bei einem
Cluster mit nur zwei Knoten ist das ja immer so eine Sache. Um diese
Anforderungen abzudecken legen wir eine erste Version der Datei
/etc/cluster/cluster.conf
an:
|
|
Was machen wir da nun genau?
- In der ersten Zeile legen wir den Namen des Clusters fest. Die Option
config_version
ist eine manuelle Versionierung der Konfiguration, die sollten (müssen) wir bei jeder Änderung erhöhen. - In der zweiten Zeile definieren wir, daß der Cluster handlungsfähig sein soll, auch wenn er kein Quorum hat.
- In den
clusternodes
-Blöcken legen wir die Mitglieder des Clusters fest. Wir verwenden für den Namen die HB-Interface, da diese den primären Kommunikationsring bilden sollen. - Mit der
altname
-Anweisung definieren wir eine zweite Multicast-Gruppe auf einem dedizierten Port und über ein anderen Interface (wir verwenden hier den Namen, unter dem der Server auch extern erreichbar ist). - Wir setzen das DLM-Protokoll auf
sctp
, da TCP mit mehr als einem Kommunikationsring nicht funktioniert. - Mit der
totem
-Zeile legen wir fest, daß der sekundäre Ring als Failover dienen soll.
Hinweis: Viele “Security”-Guidelines empfehlen, das SCTP-Protokoll zu
deaktivieren bzw. das Laden des Kernel-Moduls sctp
zu verhindern. Hat man ein
zentrales Konfigurationsmanagement wie Puppet, so tut man gut daran, hier eine
Ausnahme einzurichten. Anbieten würde sich z.B. ein facter
-Plugin, daß auf das
Vorhandensein der /etc/cluster/cluster.conf
prüft, das kann man dann recht
leicht auswerten.
Jetzt ist der Zeitpunkt gekommen, die Datei cluster.conf
auf beide
Cluster-Knoten zu verteilen und den CMAN dann via service cman start
zu
starten. Danach überprüft man, ob sich beide Cluster-Knoten sehen und ob die
Kommunikation beide Interfaces benutzt:
|
|
Die IP-Adressen werden sich natürlich unterscheiden, aber das Prinzip sollte klar sein. Jetzt ist der Moment gekommen, um zu überprüfen, wie redundant die Ringe wirklich sind. Man sabotiert also z.B. eines der HB-Interfaces (“ifdown bond1” kann das schnell erledigen), wartet ein paar Sekunden und überprüft dann erneut den Status der Ringe, um im zweiten Schritt die automatische Wiederherstellung zu testen:
|
|
Damit haben wir den unerfreulichen CMAN-Teil fast geschafft, es fehlt nur noch eine Sache: Wir benötigen noch einen Mechanismus, mit dem sich die beiden Cluster-Knoten bei Bedarf gegenseitig “in einen definierten Zustand” versetzen können, sprich, wir brauchen STONITH. Warum wir das brauchen, kann man in diesem Comic am Beispiel einer Zombie-Apokalypse sehr schön sehen. Und da wir mit CMAN eigentlich nicht allzuviel zu tun haben wollen, verwenden wir hier einen Trick: Wir reichen die Fencing-Requests einfach an Pacemaker weiter. Die vorläufig finale Version der “cluster.conf” sieht dann so aus:
|
|
Nachdem wir die Konfiguration auf beide Knoten verteilt haben, können wir CMAN
ohne Neustart dazu bewegen, die Konfiguration neu einzulesen (man achte auf die
erhöhte config_version
-Nummer):
|
|
Falls das wider Erwarten nicht klappt: Restart, Reboot… Und damit wären wir dann auch mit CMAN fertig.
Pacemaker-Grundkonfiguration
Tech-Preview sei Dank ist die Einrichtung von Pacemaker relativ trivial geworden. Nach dem Start auf beiden Knoten mit “service pacemaker start” und bis zu 30 Sekunden warten überprüfen wir den Status des Clusters:
|
|
Wir müssen nun als erstes festlegen, daß der Cluster auch dann weiter funktionieren soll, wenn er kein Quorum hat (sind ja nur zwei Knoten) und wir müssen STONITH konfigurieren. Ersteres ist trivial:
|
|
Um ein geeignetes STONITH-Medium zu finden ist es hilfreich, sich zunächst einen Überblick über alle vorhandenen Agents zu verschaffen:
|
|
Hat meinen einen Agent gefunden, der vielversprechend aussieht, so kann man sich die Detail-Informationen dazu anzeigen lassen. Für den Agent “fence_ilo_mp” (iLO ist die “Fernwartung” von HP) .z.B:
|
|
Die Fence-Devices werden jetzt in Pacemaker via der “crm”-Shell eingerichtet. Gehen wir mal davon aus, daß die iLOs via SSH angesprochen werden sollen und daß sie unter “magma1-ilo” und “magma2-ilo” erreichbar sind. Dann sieht das folgendermaßen aus:
|
|
Wir haben jetzt also zwei STONITH-Devices implementiert und mit den
Location-Constraints dafür gesorgt, daß der Agent, der magma1-hb
abschießt, auf
keinen Fall auf magma1-hb
(man beachte die Node-Namen in der pcmk_host_list
- da muß der richtige Name rein, also der mit “-hb” dran…) selbst läuft. Damit sind wir durch - der Cluster ist einsatzbereit, wir können jederzeit logische Volumes erzeugen und diese dann beliebigen virtuellen Maschinen zuordnen. Dafür benutzen wir einfach den VirtualDomain-Agent und kleben ein bißchen Shell-Kleister ausßenrum - das sei aber jedem selbst zur Übung überlassen. Natürlich ist hier noch nicht Schluß, man kann z.B. noch die Verschlüsselung des Traffics aktivieren, aber für ein paar erste Schritte reicht das Konzept dicke. Derzeit sollte das ganze so aussehen:
|
|
Hinweis: Dieser Artikel einhält eine Reihe von Tippfehlern, die es unmöglich machen, den Code wie abgebildet einfach zu pasten. Ebenso ist in der Konfiguration ein kleiner Denkfehler enthalten. Das ist Absicht - Cluster sind eine ernste Sache und jeder, der sich für einen verantwortlich zeigt, sollte gezwungen sein, seinen eigenen Hirnschmalz einzusetzen!
Ich höre mir jetzt von Chopin die “Prelude in Cis-Dur, op. 45” an, mit Vladimir Ashkenazy am Flügel… und glaubt mir, da freue ich mich richtig drauf! Schönes Wochenende!