Service Monitoring unter FreeBSD

Server mit FreeBSD zu betreiben. gefällt mir. Was allerdings ein schlechtes Gefühl hinterlässt, ist die Attitüde von FreeBSD, alles oder nichts zu liefern. In diesem Sinne gibt es beim leichtesten Husten einen Kernelpanik (der standardmäßig die Kiste hängen lässt). Für Dienste gilt ähnliches: Sie werden beim Booten gestartet und dann müssen sie allein überleben.

Leben am Limit

Keine Software ist perfekt. Wenn sie mal abstürzt, gibt es zwei Möglichkeiten damit umzugehen.

Die erste Variante besteht in einem stillen Restart des Dienstes oder der Maschine. Mit etwas Redundanz im Aufbau heilt sich ein Fehler von allein.

Die andere Variante soll den Fehler schnellstmöglich beheben. Dazu muss ein Fehler weh tun, nein, es muss richtig schmerzen. Und das ist der FreeBSD Weg.

Entdeckt der Kernel einen Fehler, so wirft er gern und schnell einen panic. Die Standardbehandlung besteht darin, Debuginfos auf die Konsole zu schreiben und das System anzuhalten. Der zuständige Admin kann dann an der Maschine selbst sehen, was vorgefallen ist und manuell neu starten.

In ähnlicher Weise wird der Userspace befüllt. Während des Boot-Prozesses werden die Dienste gemäß der rc.conf gestartet. On es klappt oder nicht, steht dabei nicht zur Debatte. Und wenn ein Dienst später mal abstürzt, dann muss der Admin auf die Maschine gehen und den Dienst manuell neu starten.

Das ist für die Produktion klar indiskutabel.

Selbstheilung

Der Umgang mit den Kernelpanics ist noch am einfachsten. Man übergibt das Handling dem Kernel Debugger und scripted dessen Verhalten.

[root@server ~]# service ddb rcvar
# ddb : DDB kernel debugger
#
ddb_enable="YES"
#   (default: "")

Die zugehörigen Scripte finden sich in /etc/ddb.conf:

# kdb.enter.panic       panic(9) was called.
script kdb.enter.panic=textdump set; capture on; run lockinfo; show pcpu; bt; ps; alltrace; capture off; call doadump; reset

Im Detail tut das folgendes:

  • Umstellen auf Textdumps, statt eines kompletten Speicherabzugs.
    Das macht Dumps deutlich schneller und kleiner, so dass sie in die Swappartition passen.
  • Dann wird der Mitschnitt der Konsolenausgabe (für den Textdump) aktiviert und verschiedene Debuginfos eingesammelt.
  • Zum Schluss wird der Mitschnitt geschlossen und in die Swappartition geschrieben.
  • Abschließend rebootet das System von allein.

Mit der folgenden Einstellung in der rc.conf werden die Dumps beim Booten (vor der Aktivierung des Swapbereiches) ausgelesen und nach /var/crash gespeichert.

# Set dumpdev to "AUTO" to enable crash dumps, "NO" to disable
dumpdev="AUTO"

Nach dem Reboot kann der Admin die Diagnoseinformation auslesen:

[root@server ~]# cat /var/crash/info.69
Dump header from device /dev/aacd0s1b
  Architecture: amd64
  Architecture Version: 1
  Dump Length: 105472B (0 MB)
  Blocksize: 512
  Dumptime: Wed Jan 25 15:25:04 2017
  Hostname: server...
  Magic: FreeBSD Text Dump
  Version String: FreeBSD ...
  Panic String:
  Dump Parity: 1769329166
  Bounds: 69
  Dump Status: good

[root@server ~]# tar xOf /var/crash/textdump.tar.69
db:0:kdb.enter.default>  show pcpu
cpuid        = 5
dynamic pcpu = 0xffffff807f3df680
curthread    = 0xffffff000ccc9000: pid 12 "swi1: netisr 5"
curpcb       = 0xffffff835f80cd10
fpcurthread  = none
idlethread   = 0xffffff0002b458c0: tid 100005 "idle: cpu5"
curpmap      = 0xffffffff80cb05d0
tssp         = 0xffffffff80d21188
commontssp   = 0xffffffff80d21188
...

Soweit so einfach.

Lost in userland

Schlimmer ist die Situation mit den verschiedenen Diensten. Es gibt keinen zentralen Weg, die benötigten Dienste automatisch neu zu starten, wenn diese durch irgendeinen Fehler abstürzen.

Einige Dienste bringen deswegen eigene WatchDog-Services mit. Andere hoffen einfach darauf, dass alles gut geht.

Es gibt einige Pakete, die sich mit dem Thema befassen, aber die sind entweder aus einer anderen Welt (wie monit), bauen auf doppelte Datenhaltung (wie fsc) oder sind komplett ungepflegt.

Ich möchte nun eigentlich die Bordmittel benutzen, um die benötigten Services regelmäßig zu prüfen und bei Bedarf neu zu starten.

Zentrale Komponente der Diensteverwaltung ist bei FreeBSD rc.conf. Man benutzt es über Scripte, vor allem den Wrapper service.

service -e listet alle aktivierten Dienste auf, allerdings etwas zu viel. So interessiere ich mich nur für die Dienste, die ein pidfile mitbringen, d.h. langfristig laufen. Die anderen Dienste sind oft nur einmalig auszuführende Einstellungen. Und dann gibt es noch Dienste, auch ohne pidfile durchlaufen. Also habe ich ein schnelles Shellscript geschrieben:

[root@server ~]# cat /usr/local/sbin/restart_services.sh
#! /bin/sh

# services which do not have a pidfile in the config
always="bird bird6"
# services which should not be checked
never=""

service -e | while read a; do
 doit=0
 for name in $always; do
   if expr "$a" : ".*/$name" >/dev/null; then
     doit=1
     break
   fi
 done
 for name in $never; do
   if expr "$a" : ".*/$name" >/dev/null; then
     doit=-1
     break
   fi
 done
 if [ "$doit" -eq 0 ]; then
   if egrep -q 'pidfile' $a; then
     doit=1
   fi
 fi
 if [ "$doit" -gt 0 ]; then
   if ! $a onestatus >/dev/null; then
     echo "Starting $a"
     $a start
   fi
 fi
done

Dieses Script prüft für jeden aktivierten (gemäß rc.conf) Dienst, ob dieser ein pidfile hat oder explizit benannt (always) wurde. Dienste, die ausgeschlossen wurden (never), werden ignoriert. Für die dann noch übrig bleibenden Dienste wird der Status abgefragt. Falls der Dienst nicht läuft, wird er gestartet.

Das Script kommt in die crontab von root:

2-58/5 * * * *  /usr/local/sbin/restart_services.sh

Und ich kann wieder ruhig schlafen.

Post a comment

Related content