Hochverfügbarkeit ad absurdum – Instant Messenger-Cluster mit DRBD und Finch (Pidgin)

Hochverfügbarkeit unter Linux wird oftmals unberechtigterweise für ein bodenloses Fass gehalten. Zugegebenermaßen bedarf der Einstieg einiger Geduld und verlangt auch Einlesungsvermögen – es ist allerdings machbar und für jeden halbwegs routinierten Administrator (oder jemanden, der es mal sein will) ein stemmbares Hindernis. Dieses Beispiel soll zeigen, wie simpel der Aufbau eines einfachen 2-Node-Clusters sein kann.

Wenn es darum geht, Daten zwischen mehreren Hosts stets synchron zu halten, ist die Verwendung eines DRBDs (Distributed Replicated Block Device) meistens die eleganteste und einfachste Lösung.

So kann man seine Server beispielsweise mit dedizierten LUNs ausstatten und auf diesen die durch den späteren Cluster zu schützende Applikationen ablegen. In Kombination mit heartbeat, Pacemaker oder ähnlichen HA-Lösungen ergibt DRBD das Herzstück für hochverfügbare Linux-Applikationen.

Das Konzept ist simpel und genial zugleich – den Möglichkeiten sind hier keine Grenzen gesetzt, wie das folgende, etwas realitätsferne, Beispiel zeigt.

Hochverfügbarkeit ad absurdum

Wer gerne online soziale Kontakte pflegt, kennt die verschiedensten Instant-Messenger, von denen Skype, ICQ und Jabber nur drei prominente Vertreter sind. Um diese Protokolle auch unter Linux zu verwenden, gibt es Multiprotokoll-Messenger, wie beispielsweise Pidgin. Von Pidgin existiert eine Variation, die keine grafische Oberfläche verwendet und stattdessen auf eine curses-Textoberfläche zurückgreift – Finch. Dieses Tool dient hier als unternehmenskritische Applikation, die mithilfe von heartbeat später in einem Active/Passive Cluster betrieben wird. Das Resultat ist ein hochverfügbarer Instant-Messenger, der im Fehlerfall auf einen zweiten Node in einem anderen Brandabschnitt wechselt – ohne dabei seine Konfiguration und Protokolle zu verlieren. Sicherlich werden sich jetzt viele Leser fragen, wie sie bisher ohne eine solche Applikation leben konnten. :)

AufbauIn diesem Beispiel gibt es zwei Raspberry Pi, die hinter jeweils einem herkömmlichen DSL-Router betrieben werden. Über eine Portfreigabe, die auf beiden Routern äquivalent einzurichten ist, ist ein Zugriff von “außen” (WAN) über SSH auf den Raspberry Pi möglich – idealerweise nimmt man hier jedoch nicht den Standardport 22. Über ein Tool namens GNU screen kann eine Terminal-Sitzung mit ausgeführten finch jederzeit fortgesetzt werden – so hat man von jedem Host mit Internetverbindung Zugriff auf die “Chat-Shell“. Die beiden Router sind in diesem Beispiel mit einem IPSec-VPN verbunden, die beiden Raspberry Pi können sich also anpingen und über einen verschlüsselten Kanal kommunizieren, obwohl sie sich in unterschiedlichen, voneinander getrennten, Netzwerksegmenten befinden.

Mithilfe eines Tools namens heartbeat wird später eine gegenseitige Überprüfung auf Verfügbarkeit durchgeführt (daher das VPN zwischen den Routern; die Clusternodes müssen einander anpingen können – eine andere Möglichkeit wäre ein Point-to-Point-VPN, beispielsweise mittels OpenVPN). Fällt ein Clusternode aus, bekommt dies der andere Node mit, übernimmt den Zugriff auf die gemeinsame Speicherressource (dazu später mehr!) und startet die Anwendung schnellstmöglich neu (entspricht dem Active/Passive Cluster-Prinzip).

Neben den zwei Raspberry Pi werden noch zwei USB-Sticks benötigt, die in diesem Aufbau das zu replizierende Blockgerät darstellen – DRBD mag keine Pseudo-devices, wie beispielsweise mit dd angelegte Dateien. Auf dieser “Cluster-Disk” werden die Konfigurations- und Protokolldateien von Finch gespeichert. So verfügt die Applikation stets über die selben Daten – unabhängig davon, wo sie gerade ausgeführt wird.

Aufbau und Netzwerk

Für dieses Beispiel habe ich mir einen NoIP-Hostname zugelegt – nach der Registrierung kann die mit dem dynamischen Hostname verbundene IP über ein NoIP-eigenes Linux-Utility aktualisiert werden. Dieses muss auf den beiden Raspberry Pi übersetzt und installiert werden:

both-nodes # apt-get install gcc curl
both-nodes # wget http://www.no-ip.com/client/linux/noip-duc-linux.tar.gz
both-nodes # tar xfz noip-duc-linux.tar.gz
both-nodes # cd noip-*
both-nodes # make && make install
...
Please enter the login/email string for no-ip.com  
Please enter the password for user '...'  ***
...
Please enter an update interval:[30]  44640
...

Standardmäßig läuft der NoIP-Client im Hintergrund – genau das wollen wir in diesem Cluster-Setup jedoch nicht. Über heartbeat erfolgt später ein geskriptetes Update im Falle eines Failovers. Wenn die Anwendung also von einem Node zum anderen wechselt, wird die IP-Adresse, mit der auf die Chat-Shell zugegriffen wird, aktualsiert. Durch eine manuelle Ausführung kann sichergestellt werden, dass das Tool ordnungsgemäß funktioniert:

any-node # /usr/local/bin/noip2 -i $(curl --silent http://icanhazip.com)
any-node # ping chat.noip.com

Für den späteren Clusterbetrieb müssen noch Software-Pakete für drbd und heartbeat installiert werden:

both-nodes # apt-get install drbd8-utils heartbeat

DRBD

Bevor der gemeinsame Clusterspeicher eingerichtet wird, ist es notwendig sicherzustellen, dass die beiden Nodes einander finden. Auch bei funktionierendem DNS sollte man hierfür immer einen lokalen Eintrag in der /etc/hosts vornehmen (um unabhängig von einem evtl. anfälligen DNS-Service zu sein) und die Nodes anpingen:

both-nodes # vi /etc/hosts
....

192.168.1.2   hostA.fqdn.dom hostA
192.168.2.2   hostB.fqdn.dom hostB

ESC ZZ

node-a # ping hostA
node-a # ping hostB
node-b # ping hostA
node-b # ping hostB

Die beiden angeschlossenen USB-Sticks werden neu partitioniert (vorhandene Partitionen werden entfernt), sie erhalten eine Linux-Partition (Typ 83). Anschließend wird die DRBD-Konfigurationsdatei angepasst:

both-nodes # fdisk /dev/sda << EOF
d
4
d
3
d
2
d
1

n
p
1

w
EOF

both-nodes # cp /etc/drbd.conf /etc/drbd.conf.initial
both-nodes # vim /etc/drbd.conf
...
resource drbd1 {
  protocol C;

  syncer {
    rate 75K;
    al-extents 257;
  }
  on hostA.fqdn.dom {
    device    /dev/drbd1;
    disk      /dev/sda1;
    address   192.168.1.2:7789;
    meta-disk internal;
  }
  on hostA.fqdn.dom {
    device    /dev/drbd1;
    disk      /dev/sda1;
    address   192.168.2.2:7789;
    meta-disk internal;
  }

}

Definiert wird hier ein Volume drbd1, welches auf den beiden Nodes hostA.fqdn.com und hostB.fqdn.com jeweils auf dem Gerät /dev/sda1 synchronisiert wird.

Sehr wichtig ist auch folgende Zeile:

rate 75K;

Sie definiert die maximale Synchronisierungsrate in Byte pro Sekunde, hier 75 KB/s. Die Synchronisierungsgeschwindigkeit ist von vielen Faktoren abhängig und sollte sorgfältig ausgewählt werden. Die Geschwindigkeit sollte beispielsweise nicht höher sein, als der verwendete Speicher es zulässt. Wenn für DRBD und die Applikation das gleiche Netzwerksegment verwendet wird (idealerweise hat man für DRBD ein eigenes Netzwerk), muss auf den üblichen Netzwerktraffic Rücksicht genommen werden.

Eine Faustregel besagt, den Wert der Syncer rate auf das 0.3-fache der effektiv verfügbaren Bandbreite zu setzen – ein Beispiel findet sich im Handbuch von DRBD:

110 MB/s Bandbreite * 0.3 = 33 MB/s
...
syncer rate = 33M;

Lässt das Netzwerk die definierte Maximalgeschwindigkeit nicht zu, wird automatisch gedrosselt. Mehr Informationen zur Synchronisation finden sich im Handbuch von DRBD: [klick mich!].

Anschließend wird einem Node das Volume angelegt, aktiviert und formattiert. Danach wird das neue Volume eingehängt:

node-a # drbdadm create-md drbd1

==> This might destroy existing data! <==
Do you want to proceed? [need to type 'yes' to confirm] yes ...

node-a # drbdadm up drbd1
node-a # drbdadm primary drbd1
node-a # mkfs.ext4 /dev/drbd1
both-nodes # mkdir /finch
node-a # mount /dev/drbd1 /finch

Auf dem anderen Node werden die Änderungen nachgezogen, was bei der initialien Synchronisierung schon etwas dauern kann (Zeit für einen Kaffee!) – in meinem Beispiel dauerte die Initialisierung eines 256 MB USB-Sticks über VPN bei 75 kbit/s Upload ca. eine Stunde – der Status kann über die Datei /proc/drbd eingesehen werden:

node-b # drbdadm connect drbd1
node-b # uptime
 16:40:30 up  2:08,  1 user,  load average: 0,20, 0,16, 0,10

both-nodes # cat /proc/drbd
version: 8.3.13 (api:88/proto:86-96)
srcversion: A9694A3AC4D985F53813A23

 1: cs:SyncTarget ro:Secondary/Primary ds:Inconsistent/UpToDate C r-----
    ns:0 nr:104320 dw:104320 dr:0 al:0 bm:6 lo:1 pe:2321 ua:0 ap:0 ep:1 wo:f oos:148564
        [=======>............] sync'ed: 42.0% (148564/252884)K
        finish: 0:32:11 speed: 64 (24) want: 71,680 K/sec

Sobald die Synchronisation abgeschlossen ist, sollte überprüft werden, ob Änderungen repliziert und Rollen problemslos gewechselt werden. Dazu wird folgendes ausgeführt:

  • Erstellen einer Datei auf dem primären DRBD-Node, MD5-Summe erstellen
  • Aushängen des Dateisystems, auf sekundäre Rolle herabstufen
  • Heraufstufen des zweiten DRBD-Nodes, Dateisystem einhängen
  • Datei finden, MD5-Prüfsumme überprüfen
  • Datei löschen und weitere anlegen
  • Zurückstufen der Rollen

In diesem Beispiel kann immer nur der primäre Node exklusiv auf das Volume zugreifen, der sekundäre Node hat keinen Zugriff auf das Volume. Soll ein Volume von beiden Nodes zeitgleich aktiv eingesetzt werden können (beispielsweise, weil ein Active/Active Cluster implementiert wird), ist ext4 hier das falsche Dateisystem. In einem solchen Fall muss ein Cluster-Dateisystem, wie GFS oder OCFS2, verwendet werden. Diese Dateisysteme bieten spezielle Locking-Mechanismen, die die Zugriffe der einzelnen Nodes auf das Volume regeln.

node-a # dd if=/dev/zero of=/finch/bla.bin bs=1024k count=1
node-a # md5sum /finch/bla.bin > /finch/bla.bin.md5sum
node-a # umount /finch
node-a # drbdadm secondary drbd1

node-b # drbdadm primary drbd1
node-b # mount /dev/drbd1 /finch
node-b # ls /finch
lost+found    bla.bin    bla.bin.md5sum
node-b # md5sum -c /finch/bla.bin.md5sum
/finch/bla.bin: OK
node-b # rm /finch/bla.bin*
node-b # dd if=/dev/zero of=/finch/foo.bin bs=1024k count=1
node-b # md5sum /finch/foo.bin > /finch/foo.bin.md5sum
node-b # umount /finch
node-b # drbdadm secondary drbd1

node-a # drbdadm primary drbd1
node-a # mount /dev/drbd1 /finch
node-a # ls /finch
lost+found    foo.bin    foo.bin.md5sum
node-a # md5sum -c /finch/foo.bin.md5sum
/finch/foo.bin: OK

Scheint wunderbar zu funktionieren! :)

Finch

Wie vorhin erwähnt, dient der Multiprotokoll-Messenger Finch (Pidgin) in diesem Fall als unternehmenskritische Applikation. Wie es sich für eine solche Applikation gehört, bekommt sie einen Serviceuser mit einer einheitlichen UID verpasst, damit das Tool nachher über heartbeat auf den Nodes geskriptet gestartet werden kann. Hierzu wird GNU Screen als Terminal-Multiplexer verwendet, um das Tool im Hintergrund zu starten und die Möglichkeit zu schaffen, remote auf die Sitzung zuzugreifen.

both-nodes # apt-get install screen finch
both-nodes # useradd -u 1337 -m -d /finch/home su-finch
both-nodes # gpasswd -a su-finch tty
both-nodes # passwd su-finch

Die Hinzufügen von su-finch in die Gruppe tty ist übrigens notwendig, damit GNU screen später auf das Terminal zugreifen kann, wenn es über den su-Mechanismus gestartet wird.

Vorab kann man finch allerdings schon mal konfigurieren und ein Instant Messenger-Konto seiner Wahl hinzufügen:

node-a # su - su-finch
node-a # screen
node-a # finch

finch (curses)Wer schon einmal Pidgin benutzt hat, wird die Buddy-Liste und Chat-Fenster wiedererkennen.

Die Fenster werden in der Regel mittels Tastenkombinationen gewechselt, in Kombination mit GNU screen besteht jedoch auch die Möglichkeit der Maussteuerung. Einige wichtige vordefinierte Tastenkombinationen:

  • nächstes Fenster: ALT + N
  • vorheriges Fenster: ALT + P
  • markiertes Fenster schließen: ALT + C
  • Kontextmenü aufrufen: F11
  • Aktionsmenü aufrufen: ALT + A
  • Menü des aktuellen Fensters aufrufen: STRG + P

heartbeat – Computer, lebst Du noch?

heartbeat dient primär, wie der Name vermuten lässt, zur Kommunikation von Clusternodes, um deren Verfügbarkeit zu gewährleisten. Das Tool kommuniziert mit benachbarten Clusternodes regelmäßig über einen verschlüsselten Tunnel und kann so schnell auf Ausfälle reagieren. Tritt ein solcher Ausfall ein, starten vorher definierte Skripte, um diesen zu kompensieren. In diesem Beispiel werden zwei Cluster-Resourcen auf dem nächsten Node neugestartet: der gemeinsame DRBD-Speicher und der Dienst finch.

STONITHIm Cluster-Betrieb kann es, je nach Größe und Applikation, erforderlich sein, sicherzustellen, dass fehlerhafte Nodes an der Wiederaufnahme ihrer Dienste gehindert werden. Dieser Mechanismus wird als STONITH (Shoot the other node in the head) bezeichnet. Es gibt zahlreiche Schnittstellen, um das “Liegenbleiben” des fehlerhaften Clusternodes zu bewerkstelligen, beispielsweise:

  • Remote-Interface des Servers (iLO, DRAC, LOM,…)
  • USV, an der der Server angeschlossen ist
  • PDU (Power Distribution Unit), über welche der Clusternode mit Strom versorgt wird
  • Blade-Enclosure Management-Schnittstelle

Wird kein STONITH angewandt, kann es im Extremfall zu Datenkorruptionen kommen, wenn beide Clusternodes (beispielsweise aufgrund eines Netzwerkausfalls) der Meinung sind, der einzig aktive Node zu sein und ihre Applikation ausführen. Implementieren lässt sich STONITH auch unter Linux – unter anderem mit heartbeat oder Pacemaker. In diesem Beispiel würde das jedoch den Rahmen der Übersichtlichkeit sprengen. ;-)

Anwendungen lassen sich mit heartbeat sehr einfach im Cluster betreiben, da zur Dienst-Steuerung auf herkömmliche Init-Skripte zurückgegriffen wird. Im Idealfall kann man einfach mit symbolischen Links arbeiten, um einen Dienst in das Cluster zu integrieren.

In diesem Beispiel wird ein benutzerdefiniertes Init-Skript angelegt, welches Finch startet und anschließend den NoIP-Hostname aktualisiert.

Zuerst wird eine clusterweite Konfigurationsdatei (/etc/ha.d/ha.cf) angelegt, in ihr werden grundlegende Parameter, wie Logdateien und Schwellwerte definiert:

node-a # vi /etc/ha.d/ha.cf
debugfile /var/log/ha-debug
logfile /var/log/ha-log
logfacility local0
keepalive 10
deadtime 30
warntime 20
initdead 60
ucast eth0 192.168.2.2
udpport 694
auto_failback off
node hostA.fqdn.dom
node hostB.fqdn.dom

ESC ZZ

node-b # vi /etc/ha.d/ha.cf
...
ucast eth0 192.168.1.2
...

ESC ZZ

Die Datei unterscheidet sich je Node in einer Zeile (ucast) – hier ist jeweils die IP-Adresse des anderen Nodes einzutragen.

Zu den einzelnen Parametern:

  • debugfile / logfile / logfacility – Debug-Log und herkömmliches Log; zu verwendende Syslog-Facility
  • keepalive – Zeitabstände in Sekunden, in denen Keepalives versendet werden
  • warntime – Zeitspanne, ab wann ein Node zu verfallen droht
  • deadtime – Zeitspanne, ab wann ein Node tot zu sein scheint
  • initdead – Zeitpunkt, ab wann ein Node aus dem Cluster entfernt wird
  • ucast – IP-Adresse, an welche über Unicast Heartbeat-Pakete versendet werden
  • udpport – UDP-Port
  • auto_failback – definiert, ob nach Wiedereintritt eines Clusternodes die Ressourcen zurückverschoben werden sollen (sofern dieser Clusternode ein präferierter Node für bestimmte Ressourcen war)
  • node – definiert die vorhandenen Clusternodes nacheinander

Da die Clusterkommunikation verschlüsselt abläuft, muss auf beiden Clusternodes eine Datei unter /etc/ha.d/authkeys angelegt werden:

both-nodes # vi /etc/ha.d/authkeys
auth 1
1 sha1 superlangesundsicherespasswort08151337666

Anschließend erfolgt eine Zuteilung der jeweiligen Cluster-Ressourcen – in der Datei /etc/ha.d/haresources:

both-nodes # vi /etc/ha.d/haresources
hostA.fqdn.dom
hostB.fqdn.dom  drbddisk::drbd1 Filesystem::/dev/drbd1::/finch::ext4    finch

Die Datei listet zunächst einmal alle Clusternodes und – durch einen Tab abgetrennt – deren primäre Ressourcen auf. In diesem Beispiel gibt es zwei Hosts, wovon der zweite der primäre Clusternode für folgende Ressourcen ist:

  • exklusiv verwendetes DRBD-Volume drbd1
  • ext4-Dateisystem auf /dev/drbd1, welches unter /finch eingehängt wird
  • Den Dienst finch (/etc/init.d/finch)

Das bedeutet: sofern beide Clusternodes zur Verfügung stehen, werden die oben genannten Ressourcen immer auf Node 2 (hostB.fqdn.dom) gestartet. Steht der Node nicht zur Verfügung, werden die Ressourcen auf Node 1 (hostA.fqdn.dom) gestartet. Ein automatisches “Zurückverschieben” der Ressourcen erfolgt aufgrund der Einstellung “auto_failback off” (in /etc/ha.d/ha.cf) nicht.

Zuletzt fehlt noch das Initskript zum Starten und Stoppen des Finch-Dienstes – wie bei herkömmlichen Diensten, wird das Skript unter /etc/init.d/finch abgelegt:

# vi /etc/init.d/finch
#!/bin/bash
#
# finch        Startup script for finch including noip update
#

start() {
        /usr/local/bin/noip2 -i $(curl --silent http://icanhazip.com) >/dev/null 2>&1
        chmod g+rw $(tty)
        su -c "screen -d -m" su-finch
        RESULT=$?
        return $RESULT
}
stop() {
        /usr/bin/killall -u su-finch
        RESULT=$?
        return $RESULT
}
status() {
        su -c "screen -ls" su-finch
        cat /proc/drbd
        dig +short foo.noip.com
        RESULT=$?
        return $RESULT
}

case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  status)
        status
        ;;
  *)
        echo $"Usage: finch {start|stop|status}"
        exit 1
esac

exit $RESULT

Das eben erwähnte Initskript kennt die Parameter start, stop und status – und dürfte damit sogar schon fast LSB-kompatibel sein. :)

Je nach Parameter wird eine GNU screen-Sitzung unter dem Benutzerkonto von su-finch (Servicebenutzer) gestartet oder beendet – bei der Verwendung des status-Parameters werden aktuelle DRBD- und IP-Zuordnungen inklusive offener Sitzungen angezeigt.

Wenn heartbeat finch-Ressourcen startet oder stoppt, wird dieses Skript verwendet.

Funktionstest

Schön, das war jetzt viel Theorie – doch wie sieht’s in der Praxis aus? Funktioniert das überhaupt?

Natürlich – und das zeigt das folgende Beweisvideo am Besten:

:D

Monitoring

Clusternode-Überwachung mit IcingaWie es sich für unternehmenskritische Anwendungen gehört, darf ein entsprechendes Monitoring nicht fehlen. Neben der Verfügbarkeit der einzelnen Nodes ist der DRBD- und heartbeat-Status von Interesse. Während sich die Verfügbarkeit des heartbeat-Dienstes kinderleicht mit dem altbekannten check_procs Nagios-/Icinga-Plugins überprüfen lässt, gibt es für DRBD auf der Webseite von MonitoringExchange ein Shell-Skript zum kostenfreien Download: [klick mich!]

Dieses Skript lässt sich ohne Probleme in Nagios bzw. Icinga einbinden und verwenden, hier beispielsweise auf einer passiven Icinga-Instanz:

# cat /etc/icinga/commands.cfg
...
# 'check_drbd' command definition
define command{
        command_name    check_drbd
        command_line    $USER2$/check_drbd -d $ARG1$ -e "Connected" -o "UpToDate" -w "SyncingAll" -c "Inconsistent"
}

# cat /etc/icinga/objects/hostA.cfg
...
define service{
        use                             generic-service
        host_name                       hostA
        service_description             HW: drbd1
        check_command                   check_drbd!1
        }

Im oben zu sehenden Beispiel wird überprüft, ob das drbd-Volume /dev/drbd1 zur Verfügung steht. Sofern die Plugin-Antwort (auf Basis der Datei /proc/drbd) nicht “Connected/UpToDate” lautet, liegt ein Fehler vor. Bei aktiver Synchronisation (SyncingAll) wird eine Warnung ausgegeben, ein inkonsistentes Volume (Inconsistent) ergibt einen Fehler.

Fazit

Zweifelsfrei ist dieses Anwendungsbeispiel eher realitätsfern und belustigend. Ich wollte damit zeigen, wie einfach die Implementation von Hochverfügbarkeit unter Linux sein kann. Es gibt viele Wege, die zum Ziel führen – mit heartbeat und DRBD ist hier nur eine von vielen HA-Konstellationen genannt. Die Thematik ist bei weitem nicht so komplex, wie oftmals fälschlicherweise angenommen. Ob nun eine Datenbank oder ein Instant-Messenger über heartbeatgeclustert” wird, ist erstmal irrelevant – der Implementationsaufwand ist überschaubar.

heartbeat gilt eher als veraltetes Tool, mit Pacemaker und OpenAIS/Corosync gibt es zwei modernere Programme, mit denen sich in Kombination mit DRBD weitaus komplexere und umfangreichere HA-Szenarien bewerkstelligen lassen.

Prinzipiell sollte man vor der Implementation von Software HA-Lösungen zuerst die Hardware-Komponenten redundant auslegen – in diesem Beispiel gibt es einige Architekturfehler, die man im Praxisfall idealerweise beheben sollte:

  • kein dediziertes Netzwerk für Node-Kommunikation (Heartbeat-Netzwerk)
  • kein redundanter Speicher für den Clusterspeicher (RAID-Volume)
  • Netzwerkadapter sind nicht redundant gehalten (keine doppelten NICs und entsprechend verbundenen Switches; LACP?)
  • keine redundante Stromversorgung

Immerhin wurden hier verschiedene Brandabschnitte gewählt (die Raspberry Pi stehen in zwei verschiedenen Wohnungen)! :)

Wer jedoch Interesse daran hat, seinen Instant-Messenger redundant zu halten, weiß ja nun, wie es geht. ;-)

Kurztipp: Cronjob-Debugging

Die Tage hatte ich das Problem, dass ein selbst geschriebenes Skript, welches Festplatten-Temperaturen überwacht und an Icinga reportet, als Cronjob nicht funktioniert. Manuell aufgerufen funktionierte es einwandfrei:

# check_hddtemp.sh /dev/sda
OK: /dev/sda has a temperature of 32 degrees celsius (thresholds 40/50)

Per Cronjob meldete mir Icinga leider andere Werte:

CRITICAL: hddtemp had a error - check hard drive name (/dev/sda)!

Um Cronjobs zu debuggen, empfiehlt es sich erstmal, das Log-Level des Cron-Dienstes zu erhöhen. Unter Debian muss dazu die Datei /etc/default/cron editiert werden:

# vi /etc/default/cron
...
# Extra options for cron, see cron(8)
# For example, set a higher log level to audit cron's work
# EXTRA_OPTS="-L 2"
EXTRA_OPTS="-L 2"

Nachdem die Änderungen übernommen wurden, wird der Dienst neu gestartet:

# service cron restart

Im Log sollte man jetzt sehen, wann welche Skripte ausgeführt werden:

# tail -f /var/log/syslog
...
13:00:01 /USR/SBIN/CRON[5047]: (root) CMD (bash /opt/icinga_inventory.sh)
13:00:16 /USR/SBIN/CRON[5045]: (root) END (bash /opt/icinga_inventory.sh)

Das Skript wird also ausgeführt und läuft 15 Sekunden – also schon mal kein abgebrochenes Programm aufgrund fehlender Rechte oder dergleichen.

Cronjobs werden in aller Regel ohne Umgebungsvariablen und leerer PATH-Variable gestartet. Was passiert, wenn das Skript ohne Umgebungsvariablen und leerer PATH-Variable gestartet wird?

# PATH="" ./check_hddtemp.sh /dev/sda
./check_hddtemp.sh: 37: cut: not found
./check_hddtemp.sh: 37: sed: not found

# PATH="/bin:/usr/bin" ./check_hddtemp.sh /dev/sda
OK: /dev/sda has a temperature of 32 degrees celsius (thresholds 40/50)

Schau an – da haben wir doch schon die Problemursache! Jetzt kann man entweder das Skript um absolute Pfade erweitern oder der crontab eine PATH-Variable mitgeben. Absolute Pfade in Skripten sind nicht immer die beste Lösung, wenn das Skript auch auf anderen Rechnern lauffähig sein soll. Hier könnten sich die Pfade ändern, was wieder Modifikationen am Skript bedeuten würde (hier ist das zwar nicht so schlimm, weil Standard-Tools im Skript verwendet werden, geht aber ums Prinzip. :P ). Schöner ist es, das Ganze per PATH-Variable zu steuern:

# crontab -e
...
PATH="/bin:/usr/bin"
...

Und siehe da, seitdem geht das Festplatten-Temperaturmonitoring auch per Cron. :)

2 TB+ Partition unter Linux partionieren

Wer eine Festplatte mit mehr als 2 TB unter Linux partionieren will, kommt mit dem altbekannten Tool fdisk leider nicht sehr weit – es unterstützt kein GPT. Mit GNU parted lässt sich das GPT-Layout auf einer Festplatte aktivieren und eine Partition erstellen:

st-storage:~# parted /dev/sda
GNU Parted 1.8.8
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) mklabel gpt
Warning: The existing disk label on /dev/sda will be destroyed and all data on
this disk will be lost. Do you want to continue?
parted: invalid token: gpt
Yes/No? Yes
New disk label type?  [msdos]? gpt
(parted) p
Model: ATA eSATA-2 External (scsi)
Disk /dev/sda: 3000GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start  End  Size  File system  Name  Flags

(parted) mkpart primary 0 3000GB
(parted) p
Model: ATA eSATA-2 External (scsi)
Disk /dev/sda: 3000GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End     Size    File system  Name     Flags
 1      17,4kB  3000GB  3000GB               primary

(parted) quit
Information: You may need to update /etc/fstab.

Das Log des Grauens

Heute hatte ich wirklich einen bescheidenen Tag – dabei fing doch alles so ruhig an heute morgen…

Wie oftmals am Wochenende (ich habe derzeit Urlaub, daher unterscheide ich momentan nicht zwischen Werk- und Wochenend-Tagen) frühstücke ich am Rechner und schaue gemütlich eine Serie zum Wachwerden. Leider stürzt VLC ab, der Prozess lässt sich nicht beenden und hindert somit Windows auch am Herunterfahren, weswegen ich den Rechner mittels gedrückter Power-Taste abwürgen muss.

Nach einem Reboot findet Windows das Netzlaufwerk nicht mehr, es lässt sich auch nicht mehr neu verbinden – weder über die Konsole noch über die grafische Oberfläche.

Ich suche stundenlang im Internet nach einer Lösungen und lese zahlreiche Tipps über Registry-Einstellungen und Kommandozeilen-Befehle, doch nichts hilft. Am Ende lässt mich Windows 3 Minuten nach jedem Login an einem schwarzen Bildschirm warten, bis es mir den Desktop präsentiert.

Mir reicht es, ich habe die Schnauze voll und sehe erstmal leider nur eine Neuinstallation als einzige Option. Dank SSD ist diese nach nicht mal 20 Minuten fertig und ich versuche es erneut. Doch auch leider schlägt das Ganze auch diesmal fehl, was mich sehr stutzig macht. Ich beschließe in den Logs des Samba-Daemons nachzuschauen und entdecke auf dem Server folgendes:

Dateisystem          Größe Benut  Verf Ben% Eingehängt auf

dev/hda1             1,9G  1,9G     0 100% /

Das erklärt natürlich einiges.. da habe ich doch bei der Installation glatt vergessen, den Log-Ordner auszulagern..

Die als Festplatten-Ersatz verbaute CF-Karte ist einfach voll gelaufen, in Folge dessen hat Samba den Start verweigert und Windows kann das Netzlaufwerk (logischerweise) nicht mappen – großes Kino.

Nach Auslagerung sieht das Ganze wieder ganz anders aus und Windows kann das Laufwerk wieder mappen:

Dateisystem          Größe Benut  Verf Ben% Eingehängt auf
/dev/hda1             1,9G  554M  1,3G  31% /

Notiz an mich: das nächste Mal bitte nicht die Logs vergessen.

WOL und Debian 4.0

Soll ein Debian-Rechner über Wake-On-Lan aus dem Aus-Zustand hochgefahren werden können, sind einige Schritte notwendig, dass dies funktioniert. Ich selbst benutze die Technik um einen Backup-Server hochzufahren und Daten zu übertragen.

  1. Das Programm ethtool ist notwendig, wird aber in den meisten Fällen nicht mitinstalliert:
    # apt-get install ethtool
  2. Als nächstes muss nachgeschaut werden, ob die Netzwerkkarte überhaupt WOL unterstützt:
    # ethtool eth1
    Settings for eth1:
            ...
            Supports Wake-on: g
            ...
  3. Mit dem ethtool kann WOL für die Schnittstelle aktiviert werden:
    ethtool -s eth1 wol g

    Damit WOL automatisch beim Start aktiviert wird, muss dieser Befehl in die /etc/rc.local (vor der exit-Zeile) eingetragen werden!

  4. Beim Herunterfahren werden die Netzwerkgeräte automatisch ausgeschaltet, das muss unterbunden werden. In der Datei /etc/init.d/halt findet man eine Variable dafür.
    NETDOWN=yes

    einfach abändern:

    NETDOWN=no
  5. Speichern und fertig! :)

Debian Lenny auf dem EEE 701(G)

So ziemlich jeder versierte (Linux-)Benutzer wird vom vorinstallierten Xandros auf dem EEE 701(G) genervt und enttäuscht sein.

Zwar läuft das Betriebsystem schnell, aber das war es dann auch. Vieles ist einfach abgespeckt und nicht zuletzt verärgert das Repo, das es dem Benutzer nicht erlaubt, z.B. Software, wie XMMS oder LXDE zu installieren. Es ist nur über “Tricks” möglich, mit welchen man das System sehr leicht “zerschießt”.

Xandros ist gut für Anfänger, aber für mehr auch nicht. Punkt. Wer den EEE also wirklich professionell benutzen will, braucht wohl auf längere Zeit eine andere Distribution.

Ich habe jahrelang Debian benutzt und halte es für eine sehr professionelle und gut gelungene Distribution. Speziell für den EEE gibt es ein angepasstes ISO-Image und einen angepassten Kernel.

Klingt gut – ein Grund mehr, sich das mal anzuschauen!

  1. ISO-Image beziehen: http://eeepc.debian.net/debian/images/debian-eeepc.img
  2. Das Image auf eine CD brennen oder auf ein USB-Gerät mittels diskdump übertragen:
    # dd if=debian-eeepc.img of=/dev/gerät

    Wichtig: Es darf keine Partitions-ID angegeben werden, sondern die reine (!) Gerätedatei – also z.B. /dev/sdb

  3. Von der CD-ROM oder dem USB-Gerät booten und den Installer mit einem Druck auf Enter starten.
  4. Die WLAN-Unterstützung arbeitet bereits einwandfrei bei der Installation, offene, WEP- und WPA-geschützte Netzwerke können zur Installation benutzt werden.Also: Netzwerkgerät auswählen und Konfiguration vornehmen (DHCP, Statisch)
  5. Anschließend werden diverse Dateien aus dem Internet übertragen und das Partionierungstool wird geladen – hier ist es wichtig, dass ext2 und nichts anderes gewählt wird.Warum?
    Im ASUS EEE PC ist eine so genannte “solid state disk“, eine SSD, verbaut – diese kann etwaig mit einer Speicherkarte verglichen werden (nur, dass die SSD etwas schneller und leistungsfähiger ist). Die Schreib-/Lesezugriffe auf diese SSD sind aber limitiert! Irgendwann ist die SSD einfach hinüber. Daher gilt es, Schreib-/Lesezugriffe zu minimieren. ext2 ist ein non-journaling Dateisystem, während ext3, reiserFS und XFS Journaling-Dateisysteme sind und mehr Speicher-/Lesezugriffe verursachen. Nun müsste man aber erstmal wissen, was ein Jornaling-Dateisystem ist:

    Ein Jornaling-Dateisystem speichert Änderungen (z.B. in einer Datei oder eine Ordner-Umbenennung) vor dem eigentlichen Schreiben auf die Festplatte in einem gewissen Speicherbereich – dem Journal. Das hat den Vorteil, dass durch ausgeprägte Techniken des Dateisystems Daten im Störfall gerettet werden können.

    (Für mehr detailierte Informationen habe ich eine Präsentation angefügt, siehe unten.)

    Das mag eine schöne Sache sein, verkürzt aber die Lebenszeit der SSD enorm. Daher ist es sinnvoll, kein Journaling-Dateisystem zu verwenden, sondern auf ext2 zurückzugreifen.

    Ein weiterer Faktor, der die Lebenszeit der SSD bestimmt, ist die Auslagerungsdatei, oder Swap. Sie wird zur Auslagerung von Prozessen, die nicht mehr in den RAM passen, benutzt. Da der EEE aber kaum für Arbeiten, die sehr viel RAM benötigen, benutzt wird, sondern wohl in den meisten Fällen einfach nur zum Surfen, Mails checken und bequemen Chatten benutzt wird, kann auch das weg.

    Bei der Partionierung also nur eine große Partition anlegen:

    Dateisystem: ext2
    Mountpoint: /
    Daten löschen: ja, Daten löschen
    Boot-Flag: ja
  6. Nach der Partionierung werden womöglich noch Benutzername und Passwort abgefragt – ich denke, diesen Schritt muss ich nicht weiter erläutern!
  7. Nach der eigentlichen Installation wird der Zweck des Rechners abgefragt – hier nur “Standard-System” und auf keinen FallDesktop-Rechner” anwählen, da sonst KDE und GNOME installiert werden. Diese beiden Desktops sind für den 701G eindeutig zu groß und langsam! (meiner Meinung nach!)
  8. Darauf hin werden noch einige Programme installiert und der Rechner daraufhin neugestartet. Nun musste bei mir das Modul der WLAN-Karte noch in die Liste der automatisch zu ladenden Module eingefügt werden. Hierfür einfach die Datei /etc/modules laden und folgenden Eintrag hinzufügen (am Besten an erster Stelle!):
    ath5k

    Danach speichern, Modul laden und die Netzwerkkonfigurationsdatei editieren:

    # modprobe ath5k
    # nano /etc/network/interfaces

    Bei mir war das Szenario relativ einfach: WLAN-Router, WPA-Key, IP per DHCP. Da ich mich mit dem EEE in keinem anderen Netzwerk einwählen werde, habe ich mich dazu entschieden, nicht lange mit wpa_supplicant zu experimentieren sondern das Netzwerk gleich fest einzustellen:

    auto wlan0
    allow-hotplug wlan0
    iface wlan0 inet dhcp
    wpa-ssid SSID_des_Routers
    wpa-psk KEY_in_Klartext

    Nun einfach speichern und das Netzwerk neustarten:

    # /etc/init.d/networking restart
  9. Die Repodatei von apt war bei mir nicht aktuell, es fehlte ein Eintrag, der hinzugefügt werden musste – hier die beiden Einträge des EEE-Repos:
    deb http://eeepc.debian.net/debian lenny main contrib non-free
    deb-src http://eeepc.debian.net/debian lenny main contrib non-free

    Der Key für das Repo muss auch noch bezogen und hinzugefügt werden:

    # wget http://eeepc.debian.net/debian/archive-key-eeepc.asc
    # apt-key add archive-key-eeepc.asc

    Bestätigt apt dies mit “OK“, kann die Repoliste aktualisiert und das System auf den neuesten Stand gebracht werden:

    # apt-get update && apt-get upgrade
  10. Der angepasste EEE-Kernel muss jetzt noch installiert werden, das Archiv von Walter’s Eckchen beziehen, entpacken und Kernel installieren:
    # ./install-701.sh
  11. Nun muss die Soundumgebung installiert werden:
    # apt-get install linux-sound-base alsa-utils

    Ist die Installation abgeschlossen, kann die Funktionalität folgendermaßen überprüft werden:

    # aplay /usr/share/sounds/alsa/Rear_Left.wav

    Ist ein Ton in angenehmer weiblicher Stimme (:P) zu hören, funktioniert die Soundkarte.
    Ist kein Ton zu hören muss eventuell der Mixer noch eingestellt werden:

    # alsamixer

    Dort dann die Regler Master, Master Mono (falls vorhanden!) und PCM auf 80 stellen und die Stummschaltung  [M] durch Drücken von M deaktivieren. Den Mixer dann mit einem Druck auf ESC beenden.

  12. Doch nun zum grafischen System, der X-Server muss her:
    # apt-get install xserver-xorg

    Dieser Befehl installiert die komplette grafische Umgebung, das kann etwas dauern.

  13. Zu X gehört natürlich auch ein Display-Manager und ein Desktop. Hier habe ich mich für SLiM und LXDE entschieden, da diese sehr ressourcenschonend und minimalistisch, aber dennoch brauchbar sind, entschieden:
    # apt-get install slim lxde

    Währendessen wird gefragt, ob gdm oder slim benutzt werden soll – hier wird natürlich slim ausgewählt.

  14. Leider wird gdm, wie aus dem vorherigen Schritt hervorgeht, bei der Installation automatisch mitinstalliert – im Nachhinein wird es wieder deinstalliert:
    # apt-get remove --purge gdm

    Da durch sparen wir fast 20 MB.

  15. Das System ist eingerichtet – allerdings fehlen noch einige alltägliche Programme:
    # apt-get install iceweasel iceweasel-l10n-de
    
    # apt-get install icedove icedove-l10n-de
    # apt-get install xpdf
    # apt-get install pidgin pidgin-otr
    # apt-get install audacious vlc
    # apt-get install unrar unrar-free unzip zip
    # apt-get install openoffice.org openoffice.org-base openoffice.org-base-core
    openoffice.org-common openoffice.org-core openoffice.org-l10n-de

    Wird Skype auch benötigt, muss dieses extern beschafft werden: http://www.skype.com/go/getskype-linux-deb

    # apt-get install libasound2 libc6 libgcc1 libqt4-core libqt4-gui libsigc++-2.0-0c2a
    libstdc++6 libx11-6
    # apt-get install -f
    # dpkg -i skype-debian_2.0.0.68-1_i386.deb

    Ist der Rechner für die Freundin, die gelegentlich fernadministrative Unterstützung benötigt (:P), ist SSH sehr nett:

    # apt-get install openssh-server
  16. Den angelegten Benutzen fehlen noch einige Rechte, so können sie z.B. nicht unbedingt gleich die Audio-Hardware benutzen und auch den Rechner nicht herunterfahren. Das ist natürlich eher kontraproduktiv – das muss noch geändert werden:
    # gpasswd -a BENUTZER dialout
    # gpasswd -a BENUTZER fax
    # gpasswd -a BENUTZER voice
    # gpasswd -a BENUTZER cdrom
    # gpasswd -a BENUTZER floppy
    # gpasswd -a BENUTZER audio
    # gpasswd -a BENUTZER video
    # gpasswd -a BENUTZER plugdev
    # gpasswd -a BENUTZER users
    # gpasswd -a BENUTZER netdev
    # gpasswd -a BENUTZER powerdev

    Nach dem nächsten Log-In des betrefflichen Benutzers stehen die fehlenden Rechte zur Verfügung.

  17. Im Verlauf der Installation wurden viele Programme und Bibliotheken installiert, die wir nicht benötigen – löschen wir sie:
    # apt-get remove --purge exim4*
    # apt-get remove --purge nfs-common
    # apt-get remove --purge cron at
    # apt-get remove --purge rsyslog
    # apt-get remove --purge openbsd-inetd
    # apt-get remove --purge linux-image-2.6.26-1-686
    # apt-get remove --purge zenity rpm
    # apt-get autoremove --purge

    Danach kann der Cache von apt gelöscht werden, somit werden einige MB mehr frei und nicht benötigte Dateien finden den Weg ins Nirwana:

    # apt-get clean

    Trotz lediglichen 4 GB Speicher ist noch über die Hälfte der Festplatte frei. Prima! :)

  18. Und fertig, jetzt darf man sich endlich freuen:
    # apt-get install libfreude && modprobe freude

    :D

Hier aufgrund Nachfrage noch ein paar Bilder/Screenshots:

Viel Spaß beim Nacharbeiten!

Danke an any0n3 für den Tip mit dem EEE-Kernel für Debian!

Präsentation über Journaling: Präsentation “Journaling”

Debian EEE-Seite mit Wiki: http://wiki.debian.org/DebianEeePC

EEE-Kernel für Debian: http://walter.flightshop.de