HowTo Linux HA-Cluster

Installation Linux HA-Cluster mit openAIS und pacemaker
======================================

Aufgabenstellung:

Usern aus dem Intranet den Zugriff auf das Internet für Dienste, die nicht proxyfähig sind, zu ermöglichen. Da es kein Default-Routing ins Internet gibt und die lokalen Netze nicht im Internet geroutet werden, musste dies über eine NAT-Firewall erfolgen. Dieser Zugriff sollte ausfallsicher zur Verfügung gestellt werden. Ein kommerzielles Produkt wurde ausgeschlossen, so blieb nur eine Linux-Firewall als HA-Cluster einzusetzen übrig. Internes Routing und die Firewallregeln sind nicht Bestandteil dieses HowTo's. Schematisch sieht es folgendermaßen aus:


(Diagram made with http://ditaa.org/ditaa/)                                 

Das private Netz an der Internet-Seite steht in diesem HowTo für Internetadressen. Die Umsetzung aufgrund dieses HowTo's erfolgt auf Basis von openSUSE, sollte aber für alle Linux-Distribution gleich sein.

Wir beginnen mit der Installation von openSuse auf zwei identischen Servern. Die Minimalkonfiguration ist ausreichend für solche Gateways. Zusätzliche Software kann später nachinstalliert werden. Mit "zypper install pacemaker" werden alle benötigten Pakete installiert. wenn nicht, dann müssen noch folgende Pakete installiert werden: "zypper install cluster-glue resource-agents openais"

pacemaker: Der Cluster-Manager, der entscheidet, welche Ressource auf welchem Rechner läuft. startet und stoppt Dienste, wird über crm (CLI ähnlich wie bei Routern/Switchen konfiguriert)
openais/corosync: Überwacht die Rechner im Cluster und kommuniziert mit pacemaker. Eine Weiterentwicklung von heartbeat.
cluster-glue & resource-agents: Stellen die Programme (Agents) zur Verfügung, die die Ressourcen starten und stoppen.

Nach der Installation in das Verzeichnis "/etc/corosync" wechseln und mit "corosync-keygen" einen Schlüssel erzeugen (kann dauern). Der Schlüssel wird in der Datei /etc/corosync/authkey abgelegt. Er wird benötigt, wenn in der "corosync.conf" die Verschlüsselung (secauth: on) eingeschaltet wird.

Konfigurationsdatei: /etc/corosync.conf

Im aktuellen Verzeichnis befinden sich 2 Beispielkonfigurationen. Die "corosync.conf.example" kopieren wir als "corosync.conf" und ändern sie wie im Beispiel gezeigt ab. Beispiel-Konfigurationsfile für HA mit zwei Rechnern und zwei Interfacen je Rechner über die die "heartbeat"-Funktion Daten austauscht:

---------------------------------------------------------- 
# Please read the corosync.conf.5 manual page
compatibility: whitetank

aisexec {
        # Run as root - this is necessary to be able to manage
        # resources with Pacemaker
        user:           root
        group:          root
}

service {
        # Load the Pacemaker Cluster Resource Manager
        ver:            0
        name:           pacemaker
        use_mgmtd:      yes
        use_logd:       yes
}

totem {
        # The only valid version is 2
        version:        2

        # How long before declaring a token lost (ms)
        token:          5000

        # How many token retransmits before forming a new configuration
        token_retransmits_before_loss_const: 10

        # How long to wait for join messages in the membership protocol (ms)
        join:           60

        # How long to wait for consensus to be achieved before starting
        # a new round of membership configuration (ms)
        consensus:      6000

        # Turn off the virtual synchrony filter
        vsftype:        none

        # Number of messages that may be sent by one processor on
        # receipt of the token
        max_messages:   20

        # Limit generated nodeids to 31-bits (positive signed integers)
        clear_node_high_bit: yes

        # Disable encryption
        secauth:        on

        # How many threads to use for encryption/decryption
        threads:        0

        # Wie soll die Überwachung erfolgen active/passive
        rrp_mode:       active

        # Optionally assign a fixed node id (integer)
        #nodeid:        1234

        interface {

                ringnumber:     0


                # The following values need to be set based on your environment
                bindnetaddr:    192.168.58.0
                mcastaddr:      226.94.1.1
                mcastport:      5405

        }

        interface {

                ringnumber:     1


                # The following values need to be set based on your environment
                bindnetaddr:    192.168.58.128
                mcastaddr:      226.94.1.2
                mcastport:      5415

        }

}

logging {
        fileline:       off
        to_stderr:      no
        to_logfile:     no
        to_syslog:      yes
        syslog_facility: daemon
        debug:          off
        timestamp:      on
}

amf {
        mode: disabled
}
----------------------------------------------------------



Wenn diese Konfiguration übernommen wird müssen im Abschnitt "interface" die "bindnetaddr", "mcastaddr" und "mcastport" geändert werden. Jedes Interface muss eine neue Ringnummer erhalten.

Wenn sich mehrere HA-Cluster im selben Netz befinden müssen die mulitcast-adressen und multicast-ports aller cluster/clustermember unterschiedlich sein. Bei den multicast-ports beträgt die schrittweite mindestens 2, da nicht nur der angegebene Port sondern auch der nächste Port genutzt wird. Die "bindnetaddr" ist die Netzadresse in dem sich das Interface befindet, über den die "heartbeat"-Funktion laufen soll. Im o.g. Beispiel haben die Interface eth0 und eth1 die Adressen 192.168.58.31/192 und 192.168.58.139/192. Die Netzadressen sind entsprechend 192.168.58.0 und 192.168.58.128.

Der rrp_mode mus bei 2 Interfacen "active" und bei mehr als zwei Interfacen "passive" sein. Ist nur ein Interface vorhanden, kann hier "none" stehen.

Nach dem Anpassen der Konfiguration müssen die Dateien "corosync.conf" und "authkey" auf den anderen Node kopiert werden. Anschließend kann man mit "rcopenais start" die Clustersoftware auf beiden Nodes starten. Mit "corosync-cftool -s" kann man die Kommunikation im Cluster überprüfen. Das Ergebnis sollte wie folgt aussehen:

# corosync-cfgtool -s
Printing ring status.
Local node ID 523909290
RING ID 0
        id      = 192.168.58.31
        status  = ring 0 active with no faults
RING ID 1
        id      = 192.168.58.139
        status  = ring 1 active with no faults



Die Überwachung läuft, aber es sind noch keine Ressourcen konfiguriert. In unserem Beispiel die HA-IP-Adresse und die Firewall für die NAT-Funktion.

Hinweis: Sollte der Befehl ein anderes Ergebnis bringen, das in etwa so aussieht, dann gibt es ein Problem mit dem Netzwerk:

# corosync-cfgtool -s
Printing ring status.
Local node ID 540686506
RING ID 0
        id      = 192.168.58.32
        status  = Marking seqid 20 ringid 0 interface 192.168.58.32 FAULTY - adminisrtative intervention required.
RING ID 1
        id      = 192.168.58.140
        status  = ring 1 active with no faults

Die Software markiert das Interface, das z.B. manuell "down" gesetzt wurde oder über das keine Statusinformationen gesendet und empfangen werden können als "FAULTY". Danach stellt sie auch jeden weiteren Datenverkehr darüber ein. Es wird zur Zeit nicht aktiv nachgesehen, ob das Interface wieder "up" ist. Ist man sich sicher, dass das Netz wieder läuft kann man mit "corosync-cfgtool -r" den Status wieder "re-enablen".

Die Konfiguration von pacemaker wird über die "crm"-Konsole gemacht. Hier wird die CIB (Cluster Information Base) definiert. Dort ist die Konfiguration des Clusters sowie Informationen zum Status abgelegt. Die Daten im CIB werden als XML abgelegt. Man kann die Konfiguration auch über entsprechende Befehle auf der Eingabeaufforderung ausführen, wir werden aber die "crm"-Konsole nutzen.

Mit dem Befehl "crm" gelangt man auf die Konsole. Der Befehl "help" zeigt alle möglichen Befehle und deren Bedeutung an. Für die Konfiguration nutzen wir "configure" und wechseln damit in den entsprechenden Modus.

Mit "show" sehen wir die bestehende Konfiguration. Dort dürfte bei einer leeren Konfiguration nur folgendes zu finden sein:

crm(live)# configure show
node fwnat-rza
node fwnat-rzb
property $id="cib-bootstrap-options" \
        dc-version="1.1.5-ecb6baaf7fc091b023d6d4ba7e0fce26d32cf5c8" \
        cluster-infrastructure="openais" \
        expected-quorum-votes="2"


Dies setzt das System automatisch. Für unser Vorhaben, einen Cluster mit zwei Rechnern, die jeweils zwei Netzwerkkarten besitzen und eine IPtables-Firewall für die NAT-Funktion haben, müssen wir folgendes konfigurieren:

Zwei HA-Adressen, jeweils eine für jede Netzwerkkarte.
Starten der IPtables auf der aktiven Firewall.
Überwachen der beiden Gateways und umschalten, wenn ein Gateway von der aktiven Maschine nicht mehr erreicht werden kann.

Zuerst werden die HA-Adresse konfiguriert. Dies geschieht mit folgenden Befehlen:

primitive ClusterIP-ext ocf:heartbeat:IPaddr params ip="192.168.58.138" cidr_netmask="26" nic="eth1" op monitor interval="15s" timeout="20s"
primitive ClusterIP-int ocf:heartbeat:IPaddr params ip="192.168.58.38" cidr_netmask="26" nic="eth0" op monitor interval="15s" timeout="20s"


Erklärung:

primitive = definiert eine Resource, die gestartet oder gestoppt werden kann, hier eben die HA-IP-Adresse
ClusterIP-ext = Bezeichnung der Resource
ocf:heartbeat:IPaddr = Agent, der genutzt werden soll, zu finden unter /usr/lib/ocf/resource.d/pacemaker und/oder /usr/lib/ocf/resource.d/heartbeat
params = parameter, die an den agent übergeben werden sollen. findet man im agent-quellcode
op monitor = Operation "monitor" soll ausgeführt werden, mit entsprechenden Parametern

Anschliessend definieren wir noch das IPtables-Script als Ressource wie folgt:

primitive failover-firewall lsb:firewall op monitor interval="15s" timeout="15s"

Hinweis: Ist das Script unter /etc/init.d/ nicht vorhanden, schlägt dieser Befehl fehl, da sofort nachgesehen wird, ob das entsprechende Script vorhanden ist.

Erklärung:

primitive = definiert eine Resource, die gestartet oder gestoppt werden kann, hier eben die HA-IP-Adresse
failover-firewall = Bezeichnung der Resource
lsb:firewall = Mit lsb:[rcscript] definieren wir, dass das Script firewall in /etc/init.d/ genutzt werden soll.
op monitor = Operation "monitor" soll ausgeführt werden, mit entsprechenden Parametern

Nun sind alle Ressourcen, die wir für die HA-Funktion benötigen definiert. Ein "show" sollte folgendes zeigen:

crm(live)configure# show
node fwnat-rza \
        attributes standby="off"
node fwnat-rzb \
        attributes standby="off"
primitive ClusterIP-ext ocf:heartbeat:IPaddr \
        params ip="192.168.58.138" cidr_netmask="26" nic="eth1" \
        op monitor interval="15s" timeout="20s"
primitive ClusterIP-int ocf:heartbeat:IPaddr \
        params ip="192.168.58.38" cidr_netmask="26" nic="eth0" \
        op monitor interval="15s" timeout="20s"
primitive failover-firewall lsb:firewall \
        op monitor interval="15s" timeout="15s"


Wir brauchen aber noch die Überwachung der beiden Gateway, damit wir sehen ob die Netzwerkverbindung funktioniert. Hierfür definieren wir 2 weitere Ressourcen mit folgenden Befehlen:

primitive ping-ext ocf:pacemaker:ping params host_list="192.168.58.151" multiplier="100" op monitor interval="10s" timeout="5s"
primitive ping-int ocf:pacemaker:ping params host_list="192.168.58.49" multiplier="100" op monitor interval="10s" timeout="5s"

Nach der Eingabe erscheint ggf. ein Hinweis, dass die Interval- und Timeout-Werte nicht den Standards entsprechen. Wir nehmen aber unsere Werte.

Erklärung:

primitive = definiert eine Resource, die gestartet oder gestoppt werden kann, hier eben die HA-IP-Adresse
ping-ext = Bezeichnung der Resource
ocf:pacemaker:ping = Agent, der genutzt werden soll, zu finden unter /usr/lib/ocf/resource.d/pacemaker und/oder /usr/lib/ocf/resource.d/heartbeat
params = parameter, die an den agent übergeben werden sollen. findet man im agent-quellcode
op monitor = Operation "monitor" soll ausgeführt werden, mit entsprechenden Parametern

Da wir die PING-Tests auf beiden Nodes gleichzeitg laufen lassen müssen, werden sie geklont. Dies erfolgt mit folgendem Befehl:

clone pingdclone-ext ping-ext meta globally-unique="false" target-role="Started"
clone pingdclone-int ping-int meta globally-unique="false" target-role="Started"

Erklärung:

clone = definiert einen Klone
pingdclone-ext = Bezeichnung des Kones
ping-ext = Name der Resource, die geklont werden soll (ist unter "primitive ping-ext" definiert)
meta = Attribute und Werte, die übergeben werden sollen.

Damit wir die HA-Adressen und die IPtables beim Wechsel der Nodes zusammen starten können, fassen wir dieses Resourcen zu einer Gruppe zusammen:

group cluster ClusterIP-int ClusterIP-ext failover-firewall meta target-role="Started"


Erklärung:

group = definiert eine Gruppe
cluster = Bezeichnung der Gruppe
ClusterIP-int ClusterIP-ext failover-firewall = Resourcen, die unter "primitive" definiert wurden und in der Gruppe sein sollen.
meta = Attribute und Werte, die übergeben werden sollen.

Wir wollen, dass die HA-Adressen und die IPtables nur auf dem Node laufen, der eine Netzwerkverbindung zu beiden Gateways hat. Damit ist die sichergestellt, dass dieser Node seine Aufgabe erfüllen kann. Dafür erzeugen wir eine "location" mit folgendem Befehl:

location fwnat_cluster_on_connected_node cluster rule $id="fwnat_cluster_on_connected_node-rule" -inf: not_defined pingd or pingd lte 0

Erkärung:

location = definiert einen "Ort"
fwnat_cluster_on_connected_node = Bezeichung des "Ortes"
cluster = Definiert die Resource, die Betroffen ist. In unserem Fall die Gruppe Cluster mit dem entsprechenden Inhalt.
rule = Definiert eine Regel
$id="fwnat_cluster_on_connected_node-rule" = Name der Regel
-inf: = die score, die erreicht werden muss für diese Regel, bei uns -inf = undefiniert
not_defined pingd or pingd lte 0 = Logischer Ausdruck, bei uns pingd-Wert nicht definiert oder größer/gleich 0

Zum Schluss müssen noch ein paar globale Parameter gesetzt werden, damit unser Vorhaben gelingt:

property stonith-enabled="false" no-quorum-policy="ignore"


Erklärung:

property = definiert cluster eigenschaften
stonith-enabled="false" = Wir haben keine "stonith"-Ressource konfiguriert, deshalb auf "false" stellen.
no-quorum-policy="ignore" = Wenn ein Node ausfällt haben wir keine Quorum mehr (expected-quorum-votes="2") somit würde der andere Node nicht starten. Um dies zu verhindern, weil wir genau das wollen, ignorieren wir die quotum-policy

Um zu verhindern, dass die Dienste nach einem Ausfall wieder auf dem ursprünglichen Node landen, setzten wir eine Art "Kosten" mit folgendem Befehl:

rsc_defaults $id="rsc-options" resource-stickiness="100"


Hiermit verbleibt in unserem Beispiel die HA-Adresse und das IPtables-Script auf dem anderen Node, auch wenn der zuvor ausgefallene wieder aktiv wird. Ein abschliessendes "show" sollte folgende Konfig zeigen:

crm(live)configure# show
node fwnat-rza \
        attributes standby="off"
node fwnat-rzb \
        attributes standby="off"
primitive ClusterIP-ext ocf:heartbeat:IPaddr \
        params ip="192.168.58.138" cidr_netmask="26" nic="eth1" \
        op monitor interval="15s" timeout="20s"
primitive ClusterIP-int ocf:heartbeat:IPaddr \
        params ip="192.168.58.38" cidr_netmask="26" nic="eth0" \
        op monitor interval="15s" timeout="20s"
primitive failover-firewall lsb:firewall \
        op monitor interval="15" timeout="15"
primitive ping-ext ocf:pacemaker:ping \
        params host_list="192.168.58.151" multiplier="100" \
        op monitor interval="10s" timeout="5s"
primitive ping-int ocf:pacemaker:ping \
        params host_list="192.168.58.49" multiplier="100" \
        op monitor interval="10s" timeout="5s"
group cluster ClusterIP-int ClusterIP-ext failover-firewall \
        meta target-role="Started"
clone pingdclone-ext ping-ext \
        meta globally-unique="false" target-role="Started"
clone pingdclone-int ping-int \
        meta globally-unique="false" target-role="Started"
location fwnat_cluster_on_connected_node cluster \
        rule $id="fwnat_cluster_on_connected_node-rule" -inf: not_defined pingd or pingd lte 0
property $id="cib-bootstrap-options" \
        dc-version="1.1.5-ecb6baaf7fc091b023d6d4ba7e0fce26d32cf5c8" \
        cluster-infrastructure="openais" \
        expected-quorum-votes="2" \
        stonith-enabled="false" \
        no-quorum-policy="ignore"
rsc_defaults $id="rsc-options" \
        resource-stickiness="100"


Um unsere Eingaben auf den Nodes zu aktivieren, also in die Live-Konfiguration zu schieben setzen wir den Befehl "commit" ab. Danach ist auf allen Nodes die Konfiguration aktiv. Mit "end" verlassen wir die Konfigurationsebene und konnen uns mit dem Befehl "status" den aktuellen Status des Cluster ansehen:

crm(live)# status
============
Last updated: Thu May 26 14:21:39 2011
Stack: openais
Current DC: fwnat-rza - partition with quorum
Version: 1.1.5-ecb6baaf7fc091b023d6d4ba7e0fce26d32cf5c8
2 Nodes configured, 2 expected votes
3 Resources configured.
============

Online: [ fwnat-rzb fwnat-rza ]

 Resource Group: cluster
     ClusterIP-int      (ocf::heartbeat:IPaddr):        Started fwnat-rza
     ClusterIP-ext      (ocf::heartbeat:IPaddr):        Started fwnat-rza
     failover-firewall  (lsb:firewall): Started fwnat-rza
 Clone Set: pingdclone-ext [ping-ext]
     Started: [ fwnat-rza fwnat-rzb ]
 Clone Set: pingdclone-int [ping-int]
     Started: [ fwnat-rza fwnat-rzb ]



Nützliche Befehle im Betrieb:

crm_mon    = Zeigt den Status der Nodes und Ressourcen an, aktualisiert sich automatisch
crm_mon -1 = Zeigt den Status der Nodes und Ressourcen einmalig an.
corosync-cfgtool -s = Zeigt den Ring-Status an
corosync-cfgtool -r = Setzt den Ring-Status zurück, z.B. nach einem Netzwerkausfall

Nützliche Kommandos in der crm:

help = Zeigt Befehle und deren Bedeutung an
status     = Zeigt den Status der Nodes und Ressourcen einmalig an.
node standby "nodename" = Setzt den Node "nodename" in den Standby-Modus
node online "nodename"  = Setzt den Node "nodename" in den Online-Modus

Quellen:

Clusterbau: Hochverfügbarkeit mit pacemaker, OpenAIS, heartbeat und LVS von Michael Schwartzkopff (O'REILLY)
http://www.clusterlabs.org/wiki/Example_configurations
http://www.clusterlabs.org/doc/en-US/Pacemaker/1.1/html/Clusters_from_Scratch/index.html

This page was last modified on 11/08/2011 at 13:41.