HA Cluster erstellen
Voraussetzungen
Für das hier gezeigte Setup müssen folgende Dinge vorhanden/installiert sein:
Grundeinstellungen
Die Server haben folgende IP-Adresse bzw Hostnamen
IP | Hostname |
---|---|
172.30.0.221 | cluster01 |
172.30.0.222 | cluster02 |
172.30.0.224 | failover_ip |
Da es zu einem Ausfall eines DNS-Servers kommen kann und die Cluster sich nicht mehr über den Namen erreichen können, ist es wichtig das ganze auch in die /etc/hosts einzutragen (auf beiden Nodes):
echo "172.30.0.221 cluster01" >> /etc/hosts; echo "172.30.0.222 cluster02" >> /etc/hosts
DRBD konfigurieren
In der /etc/drbd.conf steht eigentlich nur folgendes:
include "drbd.d/global_common.conf";
include "drbd.d/*.res";
die /etc/drbd.d/global_common.conf sieht wie folgt aus:
global {
# usage-count yes;
usage-count no; # wenn auf yes gesetzt wird dies dem hersteller (linbit) gemeldet das die software genutzt wird, rein aus statistik-zwecken)
}
common {
syncer {
rate 100M; # dies sind Bytes, also 100M entsprechen fast einem 1GBNetzwerk
}
##
## den rest brauch man eigentlich nicht
handlers {
# These are EXAMPLE handlers only.
# They may have severe implications,
# like hard resetting the node under certain circumstances.
# Be careful when chosing your poison.
# pri-on-incon-degr "/usr/lib/drbd/notify-pri-on-incon-degr.sh; /usr/lib/drbd/notify-emergency-reboot.sh; echo b > /proc/sysrq-trigger ; reboot -f";
# pri-lost-after-sb "/usr/lib/drbd/notify-pri-lost-after-sb.sh; /usr/lib/drbd/notify-emergency-reboot.sh; echo b > /proc/sysrq-trigger ; reboot -f";
# local-io-error "/usr/lib/drbd/notify-io-error.sh; /usr/lib/drbd/notify-emergency-shutdown.sh; echo o > /proc/sysrq-trigger ; halt -f";
# fence-peer "/usr/lib/drbd/crm-fence-peer.sh";
# split-brain "/usr/lib/drbd/notify-split-brain.sh root";
# out-of-sync "/usr/lib/drbd/notify-out-of-sync.sh root";
# before-resync-target "/usr/lib/drbd/snapshot-resync-target-lvm.sh -p 15 -- -c 16k";
# after-resync-target /usr/lib/drbd/unsnapshot-resync-target-lvm.sh;
}
startup {
# wfc-timeout degr-wfc-timeout outdated-wfc-timeout wait-after-sb
}
options {
# cpu-mask on-no-data-accessible
}
disk {
# size max-bio-bvecs on-io-error fencing disk-barrier disk-flushes
# disk-drain md-flushes resync-rate resync-after al-extents
# c-plan-ahead c-delay-target c-fill-target c-max-rate
# c-min-rate disk-timeout
}
net {
# protocol timeout max-epoch-size max-buffers unplug-watermark
# connect-int ping-int sndbuf-size rcvbuf-size ko-count
# allow-two-primaries cram-hmac-alg shared-secret after-sb-0pri
# after-sb-1pri after-sb-2pri always-asbp rr-conflict
# ping-timeout data-integrity-alg tcp-cork on-congestion
# congestion-fill congestion-extents csums-alg verify-alg
# use-rle
}
}
Jetzt kommt die wichtigste Einstellung, die Ressource. Man sollte der Ressource einen passenden Namen geben und sie muss auf .res enden, hier das Beispiel für die /etc/drbd.d/data.res
resource daten { #wie die Ressource heisst, ist später auch wichtig für das Management
device /dev/drbd0; # das Device wo man später drauf zugreift
disk /dev/sdb1; # das Gerät was DRBD für die replikation nuten soll ACHTUNG!! es muss leer sein, ansonsten werden alle Daten daruaf gelöscht!
meta-disk internal; # wo die Meta-Daten gespeichert werden sollen, hier auf dem Gerät selbst
#es folgt nun die config die namen müssen zu den IP-Adressen passen, die Ports müssen gleich sein
# wenn die 'disk' auf beiden Server unterschiedlich ist, kann man diese hier entsprechend wie oben angeben und anpassen
on cluster01 {
address 172.30.0.221:7790;
}
on cluster02 {
address 172.30.0.222:7790;
}
}
Die Konfiguration muss auf beiden Servern gleich sein.
Anschliessend können wir auf beiden Server den DRBD Service starten, anschliessend schauen wir uns den Status dazu an.
/etc/init.d/drbd start
cat /proc/drbd
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by phil@fat-tyre, 2013-02-05 15:35:49
0: cs:Connected ro:Secondary/Secondary ds:Inconsistent/Inconsistent C r-----
ns:0 nr:744 dw:744 dr:0 al:0 bm:4 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
Die Ausgabe zeigt uns das niemand weiss wer der Primary ist und das die Daten inkonsistent sind, was logisch ist da aktuell noch nicht bekannt ist, von wo nach wo die Daten Synchron gehalten werden sollen. Auf dem Server der Primary werden soll, einfach folgendes ausführen:
drbdadm -- --overwrite-data-of-peer primary daten
Wenn wir jetzt etwas warten sollte der Status folgendes sagen:
cat /proc/drbd
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by phil@fat-tyre, 2013-02-05 15:35:49
0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
ns:2786 nr:2083 dw:4903 dr:28733 al:8 bm:10 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
Primary-Server ist da und die Daten sind alle aktuell, nun kann ein Dateisystem angelegt werden, ein Ordner erstellt werden und das ganze Mounten, Test-Datei erstellen, in Secondary schalten
mkfs.ext3 /dev/drbd0
mkdir /daten
mount /dev/drbd0 /daten
echo "test" > /daten/test.txt
drbdadm secondary daten
auf dem anderen Server
drbdadm primary daten
mkdir /daten
mount /dev/drbd0 /daten
ls /daten
Man sollte jetzt auf den anderen Server die erstellte Datei sehen, somit klappt das ganze auch.
corosync/pacemaker einrichten
Debian bringt schon eine Beispiel Konfiguration mit, die man auch nutzen kann.
cp /etc/corosync/corosync.conf.example /etc/corosync/corosync.conf
Unsere Config sieht wie folgt aus (cluster01):
# 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)
# you would set it to 'yes', the new option 'new' means wiping
# off the highest bit in network order to avoid possible nodeid
# conflicting.
clear_node_high_bit: new
# secauth: Enable mutual node authentication. If you choose to
# enable this ("on"), then do remember to create a shared
# secret with "corosync-keygen".
secauth: off
# How many threads to use for encryption/decryption
threads: 0
# Optionally assign a fixed node id (integer)
# nodeid: 124
# interface: define at least one interface to communicate
# over. If you define more than one interface stanza, you must
# also set rrp_mode.
interface {
# Rings must be consecutively numbered, starting at 0.
ringnumber: 0
# This is normally the *network* address of the
# interface to bind to. This ensures that you can use
# identical instances of this configuration file
# across all your cluster nodes, without having to
# modify this option.
bindnetaddr: 172.30.0.221
# However, if you have multiple physical network
# interfaces configured for the same subnet, then the
# network address alone is not sufficient to identify
# the interface Corosync should bind to. In that case,
# configure the *host* address of the interface
# instead:
# bindnetaddr: 192.168.1.1
# When selecting a multicast address, consider RFC
# 2365 (which, among other things, specifies that
# 239.255.x.x addresses are left to the discretion of
# the network administrator). Do not reuse multicast
# addresses across multiple Corosync clusters sharing
# the same network.
mcastaddr: 239.255.1.1
# Corosync uses the port you specify here for UDP
# messaging, and also the immediately preceding
# port. Thus if you set this to 5405, Corosync sends
# messages over UDP ports 5405 and 5404.
mcastport: 5405
# Time-to-live for cluster communication packets. The
# number of hops (routers) that this ring will allow
# itself to pass. Note that multicast routing must be
# specifically enabled on most network routers.
ttl: 1
}
}
logging {
# Log the source file and line where messages are being
# generated. When in doubt, leave off. Potentially useful for
# debugging.
fileline: off
# Log to standard error. When in doubt, set to no. Useful when
# running in the foreground (when invoking "corosync -f")
to_stderr: no
# Log to a log file. When set to "no", the "logfile" option
# must not be set.
to_logfile: no
#logfile: /var/log/cluster/corosync.log
# Log to the system log daemon. When in doubt, set to yes.
to_syslog: yes
syslog_facility: daemon
# Log debug messages (very verbose). When in doubt, leave off.
debug: off
# Log messages with time stamps. When in doubt, set to on
# (unless you are only logging to syslog, where double
# timestamps can be annoying).
timestamp: off
logger_subsys {
subsys: AMF
debug: off
}
}
Wichtig hierbei sind eigentlich nur folgende Parameter. Hier muss root drin stehen, sonst funktioniert das komplette HA nicht
aisexec {
# Run as root - this is necessary to be able to manage
# resources with Pacemaker
user: root
group: root
}
totem {
token: 5000 #ab wann wird ein Node als "tot" erklärt und der andere Node übernimmt die rolle
interface {
bindnetaddr: 172.30.0.221 # IP-Adresse des aktuellen Nodes
mcastaddr: 239.255.1.1 #Multicast adresse muss auf beiden Nodes gleich sein
Die Config kann dann so auf das andere System kopiert werden, dort muss dann bindnetaddr auf den anderen Node angepasst werden. Wir müssen jetzt ins /etc/corosync Verzeichnis wechseln und einen Key erstellen damit die Nodes auch wissen das sie es mit dem richtigen zu tun haben:
cd /etc/corosync/
corosync-keygen
chmod 400 authkey
scp authkey cluster02:/etc/corosync/
Anschliessend starten wir corosync und fügen es auch gleich zum "auto"start hinzu (auf beiden Nodes):
/etc/init.d/corosync start
Anschliessend prüfen wir den Status des ganzen, wichtig ist hier das unten die beiden Nodes als Online drin stehen, dann ist alles korrekt konfiguriert:
crm status
Last updated: Wed Aug 14 09:59:15 2013
Last change: Tue Aug 13 15:53:03 2013 by root via cibadmin on cluster02
Stack: classic openais (with plugin)
Current DC: cluster02 - partition with quorum
Version: 1.1.9-2db99f1
2 Nodes configured, 2 expected votes
0 Resources configured.
Online: [ cluster01 cluster02 ]
HA konfigurieren
Wenn jetzt alles soweit läuft können wir uns daran machen, die Dienste Hochverfügbar zu machen. Dafür wird Pacemaker verwendet, dieser ist der ClusterResourceManager, dazu passend gibts das Programm crm, was auch eine eigene Shell bei hat, dies hat den Vorteil das es dort Tab-Completion gibt und auch die verfügbaren Kommandos zeigt. Wir arbeiten hier mit der CRM-Shell, da es einfacher und übersichtlicher ist.
crm-Shell Bedienung (kurz Einführung)
Wenn man nur crm eingibt kommt man in die oberste Ebene der crm-Shell, wenn man dort help eingibt, sieht man aktuelle commandos:
crm
crm(live)# help
This is crm shell, a Pacemaker command line interface.
Available commands:
cib manage shadow CIBs
resource resources management
configure CRM cluster configuration
node nodes management
options user preferences
history CRM cluster history
site Geo-cluster support
ra resource agents information center
status show cluster status
help,? show help (help topics for list of topics)
end,cd,up go back one level
quit,bye,exit exit the program
crm(live)#
Man kann jetzt configure eingeben und landet dort dann in der shell. Dort steht dann nicht mehr nur "crm(live)#" sondern "crm(live) configure". Hier kann man wieder help eingeben und sieht dann die entsprechende Hilfe. Wenn man eine Primitive anlegt kann man steht Tab nutzen und er zeigt einen die aktuellen Möglichkeiten an. Voraussetzung ist, man befindet sich nicht in der obersten crm-Shell ('crm(live)#'). Um eins wieder nach oben zu kommen einfach 'up' eingeben.
Man kann von der Linux-Shell auch gleich in einem unterpunkt von crm gehen, indem man das ziel mit angibt, also "crm configure" kommt man gleich ins configure-Menü. Alle Kommandos die man in der CRM-Shell eingibt, kann man auch von der Linux-Shell machen. Allerdings ohne Tab-Completion und man muss immer mit angeben in welchen Menü man das macht. Bsp: crm configure show
Alles was man in crm anlegt ist live und wird entsprechend sofort übertragen, was manchmal zu einem merkwürdigen verhalten führen kann. Man kann dies Unterbinden indem man eine cib anlegt, das geht wie folgt:
crm(live)# cib new test_config
INFO: test_config shadow CIB created
crm(test_config)# ALLES KONFIGUREIEREN WAS MAN MÖCHTE
crm(test_config)configure# verify #prüfen ob alles korrekt ist
crm(test_config)configure# end
There are changes pending. Do you want to commit them? y
crm(test_config)#
crm(test_config)# cib use live
crm(live)# cib commit test_config
INFO: commited 'test_config' shadow CIB to the cluster
crm(live)# quit bye
Ressourcen anlegen
Man sollte sich hier evtl. ganz altmodisch genau aufschreiben was man alles in HA haben möchte, wie man die Ressource genannt hat, wie die Gruppen heissen, etc. Ansonsten kann es sein das man selbst nicht mehr weiss was, wie, wo zusammen hängt. IP-Adresse Wir gehen dazu in die crm-Shell unter configure und erstellen dort die Ressource/primitve:
bash #: crm configure
crm(live)configure# primitive failover_ip ocf:heartbeat:IPaddr2 params ip="172.30.0.224" cidr_netmask="16" op monitor interval="3s"
crm(live)configure# show
node cluster01
node cluster02
primitive failover_ip ocf:heartbeat:IPaddr2 \
params ip="172.30.0.224" cidr_netmask="16" \
op monitor interval="3s" \
crm(live)configure#
Der Name failover_ip ist frei gewählt, die IP Adresse ist hier die 172.30.0.224 und die Subnetzmaske ist 255.255.0.0 in CIDR-Schreibweise,
DRBD
Um DRDB hochverfügbar zu machen sind mehrere Schritte nötig, zum einen die Master-Rolle tauschen, bzw neu vergeben und zum anderen das Mounten und das ganze muss dann noch in der richtigen Reihenfolge passieren bzw darf nur gemountet werden wenn auch Primary aktiv ist. Zuerst erstellen wir die Ressourcen drbd, die dafür sagt das der neue Knoten primary wird, anschliessend wird das drbd-device gemountet zum Schluss wird noch eine Master/Slave-Resource hinzugefügt(ms) diese sorgt dafür das es nur einen Master geben darf
primitive drbd ocf:linbit:drbd params drbd_resource="daten"
primitive drbd_mount ocf:heartbeat:Filesystem params device="/dev/drbd0" directory="/daten" fstype="ext3"
ms masterdrbd drbd meta master-max="1" master-node-max="1" clone-max="2" clone-node-max="1" notify="true"
Jetzt sorgen wir dafür das beide Resourcen immer nur zusammen genutzt werden können, das passiert mit dem Wort colocation:
colocation mountDRBD inf: drbd_mount masterdrbd:Master
anschliessend müssen wir dafür sorgen das dies auch in der richtigen Reihenfolge passiert:
order mouten_danach inf: masterdrbd:promote drbd_mount:start
MySQL
Bei mysql ist darauf zu achten, dass das Datadir auf den richtigen Ordner zeigt. Nn unserem Fall auf /daten/mysql, wobei der Ordner mysql noch angelegt werden muss. Nach einem Neustart von mysql sollte dort alles vorhanden sein. Da aber ab sofort Pacemaker die Steuerung von mysql übernimmt sollte man dies aus dem systemstart rausnehmen und anhalten:
/etc/init.d/mysql stop
Zuerst erstellen wir wieder die Ressource für mysql:
primitive mysqlserver lsb:mysql
### man kann aber auch folgende nehmen(wobei ocf immer bevorzugt genommen werden sollte)
primitive mysqlserver ocf:heartbeat:mysql
mirth
(BtW: Mirth ist ein Kommunikationsserver der im medizinischen Bereich genutzt wird, vorwiegend für Kollungen zwischen Krankenhäusern und Laboren) Es ist darauf zu achten das unbedingt das RPM-Package von Oracle-Jave installiert wird. Mit einer anderen Java-Version geht Mirth nicht, zudem sollte das Start-Script von mirth unter /etc/init.d/ liegen bzw ein Link davon. Nur so lässt sich Mirth über Pacemaker starten und stoppen, wenn das der fall ist wie gehabt die Ressource anlegen:
primitive mirth_start lsb:mcservice
Ordnung schaffen
Nun gibt es 2 Möglichkeiten. Man kann colocations und order nehmen um dafür zu sorgen in welcher Reihenfolge etwas gestartet wird bzw welche Dienste immer zusammen hängen. Oder man macht dies in gruppen, also groups - wobei der letztere weg die leichtere und vor allem übersichtlichere Möglichkeit ist. Weiter oben bei DRBD hab ich ja schon gezeigt wie es mit Colocation und Order geht. Wir müssen jetzt also dafür sorgen das die IP-Adresse, DRBD, mysql und mirth starten und zwar genau in der genannten reihenfolge, das ganze würde dann so aussehen:
group complete_start failover_ip drbd_mount mysqlserver mirth_start
Es existiert jetzt die Gruppe "complete_start" wo die Angegebenen Ressourcen in der Reihenfolge starten und umgekehrter Reihenfolge stoppen. Mit der Ressourcen Konfiguration sind wir jetzt fertig, allerdings müssen wir an Pacemaker selbst noch ein paar Dinge einstellen:
property no-quorum-policy=ignore #Quorum ignorieren (da ein 2-Knoten Cluster gebaut wird)
property default-resource-stickiness=100 #Standard Stickiness für Resourcen ist 100 - Resource bleibt nach Umzug auf einen anderen Knoten dort 'kleben'
anschliessend geben wir exit ein und beantworten die fragen ob die Einstellungen übernommen werden sollen mit yes beantworten, das ganze sollte jetzt so (ähnlich) aussehen:
crm status
Last updated: Wed Aug 14 12:14:11 2013
Last change: Tue Aug 13 15:53:03 2013 by root via cibadmin on cluster02
Stack: classic openais (with plugin)
Current DC: cluster02 - partition with quorum
Version: 1.1.9-2db99f1
2 Nodes configured, 2 expected votes
6 Resources configured.
Online: [ cluster01 cluster02 ]
failover_ip (ocf::heartbeat:IPaddr2): Started cluster02
Master/Slave Set: masterdrbd [drbd]
Masters: [ cluster02 ]
Slaves: [ cluster01 ]
mysqlserver (lsb:mysql): Started cluster02
drbd_mount (ocf::heartbeat:Filesystem): Started cluster02
mirth_start (lsb:mcservice): Started cluster02
Man kann jetzt die aktuellen Server stoppen und man würde sehen das dieser auf den anderen Server umschwenkt. Dies kann man gut sehen wenn man crm_mon ausführt.
Troubleshooting
Ich hatte anfangs andauernd das Problem das nichts gestartet wurde und immer da stand "not installed" so wie hier:
crm status
Last updated: Mon Aug 12 18:34:22 2013
Last change: Mon Aug 12 18:34:14 2013 by root via crm_attribute on cluster02
Stack: classic openais (with plugin)
Current DC: cluster02 - partition with quorum
Version: 1.1.9-2db99f1
2 Nodes configured, 2 expected votes
5 Resources configured.
Online: [ cluster01 cluster02 ]
failover_ip (ocf::heartbeat:IPaddr2): Started cluster01
Failed actions:
drbd_mount_start_0 (node=cluster01, call=29, rc=5, status=complete): not installed
mysqlserver_start_0 (node=cluster02, call=123, rc=5, status=complete): not installed
drbd_mount_start_0 (node=cluster02, call=180, rc=5, status=complete): not installed
Zunächst sollte man prüfen ob man die Dienste wirklich starten/stoppen kann, vor allem bei Mirth sollte man das prüfen. Wenn dies alles erfolgreich geht und der Fehler immer noch vorhanden ist, sollte man sich die config anschauen und evtl den Befehl "crm configure verify" absetzen um zu prüfen ob alles OK ist. Wenn dort auch keine Fehler sind, dann bitte folgendes machen:
crm resource cleanup RESOURCE
Wobei RESOURCE für die Resource steht wo es Probleme gibt.