Überwachungstools von der Stange bieten oft viel zu viele Funktionen oder gerade nicht das Gewünschte. Mithilfe konventioneller Shellskripte bauen Sie sich individuelle Überwachungsroutinen aber leicht selbst.
Egal, ob Sie eine Heizungsanlage, einen Webserver, Datenbanksysteme, Netzwerkverbindungen, Benutzer, Lüfter oder die Rechnertemperatur automatisch überwachen und steuern möchten: Mit einfachen Shell-Routinen funktioniert das in der Regel zuverlässig und schnell. Einmal erstellte Skripte lassen sich dabei leicht für unterschiedliche Distributionen und Situationen anpassen.
Doch die Überwachung will durchdacht sein: Im Falle der eingangs erwähnten Überwachung eines Webservers genügt es nicht, nur zu prüfen, ob der Dienst läuft – schon der Fragestellung fehlt jegliche Präzision. Läuft die Hardware? Um das festzustellen, reicht ein schlichtes ping. Eine positive Antwort bedeutet aber noch lange nicht, dass der Webserver-Daemon funktioniert. Dafür müssten Sie zum Beispiel lokal auf dem Server den Prozessstatus abfragen (ps -C Dienst oder etwa service Dienst status).
Doch damit wissen Sie immer noch nicht, ob Nutzer die Daten des Webservers auch wirklich abrufen können. Dies müssten Sie regelmäßig manuell per Browser oder besser automatisch mit einem Kommandozeilenwerkzeug kontrollieren – und zwar idealerweise von außerhalb der eigenen geschützten Netzwerkinfrastruktur. Andernfalls riskieren Sie, sich durch Fehlinterpretationen in falscher Sicherheit zu wiegen – wenn etwa ein Router nicht mehr funktioniert.
Sensoren
Beim Überwachen von Programmausführungen gilt es, auf die Exit-Codes zu achten, die Terminalanwendungen und Kommandos in der Regel nach dem planmäßigen oder unplanmäßigen Ende des Programms ausgeben. Der Wert 0 steht dabei in der Regel für einen erfolgreichen Durchlauf, andere Codes für einen mehr oder weniger gravierenden Fehler. Die Tabelle “Prüfwerkzeuge” stellt eine kleine Auswahl von gängigen Tools zur Systemüberwachung vor.
Prüfwerkzeuge
| Prüfziel | Werkzeug |
|---|---|
| Erreichbarkeit von Webseiten | httping(1) |
| Datenbank-Shellclient für PostgreSQL-RDBMS | psql |
| Erreichbarkeit von Rechnern | ping |
| Namensauflösung | host |
| Angemeldete Benutzer | users |
| Dienstestatus (SysVinit) | /etc/init.d/Dienst status |
| Dienstestatus (Systemd) | systemctl status Dienst |
| Plattenspeicherplatz | df |
| Temperatur | sensors |
| Lüfteraktivität | sensors(2) |
| Portzugriffe | netread(3) |
| (1) Paket httping; (2) Paket lm-sensors; (3) Paket netrw | |
Wie das Beispiel der Überwachung eines Webservers zeigt, verursacht das Monitoring in manchen Fällen ein wenig Aufwand (Abbildung 1). In diesem Fall läuft idealerweise die Überwachung nicht innerhalb des Hauses, sondern außerhalb der eigenen IT-Infrastruktur, sodass Ausfälle nicht auch gleich das Überwachungssystem lahmlegen. Damit decken Sie aber auch fast alle Fälle von Störungen ab: Websperren, Überlastungsangriffe, allgemeine Netzüberlastung und selbst den Fall einer physikalischen Netzabtrennung durch den sprichwörtlichen Bagger.
Als Reaktion könnten Sie (automatisch) das Anfahren einer redundanten Anlage an anderer Stelle beziehungsweise mit anderer Anbindung an das Internet veranlassen. Listing 1 zeigt einen Ansatz, der als erste Reaktion zur Fehlereingrenzung bereits weitere Fragen abklärt (DNS-Problem, Netzwerkanbindung und mehr). Das Skript lässt sich bei Bedarf sehr einfach erweitern. Beachten Sie dabei die Stolperfalle, dass manche Internetanbieter beim Aufruf einer nicht erreichbaren Internetseite versuchen, Ihnen mit einer Navigationshilfe unter die Arme zu greifen. Werten Sie hier unbedingt den HTTP-Statuscode mit aus.
Listing 1
#! /bin/sh
HOST=www.example.com
IP=93.184.216.34
while true; do
# Webseite abrufen, Ausgabe in Variable
B=$(httping -G -g $HOST -c 1 -s -m)
# Exit-Code in Variable speichern
A=$?
# Ausgabe von httping aufteilen
C=$(echo $B | cut -d \ -f1)
D=$(echo $B | cut -d \ -f2)
# Ausgabe der Variablen
echo "Exit-Code: $A"
echo "STATUS: $C"
# Namensaufloesung pruefen
if [ "$C" = "-1" ]; then
host $HOST
# Exit-Code speichern ...
NA=$?
# ... und auswerten
if [ $NA = 0 ]; then
echo "Namensaufloesung ok"
else
echo "Fehler bei Namensauflösung"
# Erreichbarkeit per IP-Adresse?
ping -c 1 -q $IP
# Exit-Code speichern ...
E=$?
# ... und auswerten
if [ $E -eq 0 ]; then
echo "Rechner im Netzwerk erreichbar"
else
echo "Rechner nicht im Netzwerk erreichbar"
fi
fi
fi
# Hinweis, falls Seite nicht abrufbar
if [ $D -ne 200 ]; then
echo "Seitenfehler $D"
fi
sleep 15
done
Das im Skript ausgeführte Kommando httping (meist im Paket httping) ruft die angegebene Webseite ab und zeigt zusätzliche Informationen an, wie etwa die Latenz (siehe Kasten “Webserver anpingen”). So lässt sich ein Webserver sehr leicht auf seine Funktion hin überwachen. Das gezeigte Systemüberwachungsskript stellt die Sensorikseite der Überwachung dar, üblicherweise ist die Reaktionsseite in ein zweites Skript ausgelagert.
Webserver anpingen
Das Programm Httping hilft, den Zugriff auf einen Webserver zu prüfen. Optional ermittelt es auch das Antwortzeitverhalten, sofern Sie die Verbindung nicht über einen Proxyserver führen oder mittels der Option -G den kompletten Seiteninhalt übertragen lassen; das würde die Antwortzeiten verfälschen. Der grundsätzliche Aufruf erfolgt in der Form httping -g URL, wobei Sie mit der Option -p Port einen anderen Port also den üblichen Port 80 angeben.
Httping erzeugt auf Wunsch neben den Exit-Codes (0 = Funktion, 127 = Fehler) noch weitere Ausgaben wie die Antwortzeit, die im Fehlerfall den Wert -1 annimmt. Einer Variable übergeben, lösen Sie auf Basis dieser Ergebnisse entsprechende Alarme oder Reaktionen aus. Zum besseren Verständnis der Funktion starten Sie das kleine Beispielskript aus Listing 2 auf einem Rechner. Die entsprechenden Ausgaben zeigt Listing 3.
Der erste Aufruf zielt auf eine allgemein funktionierende Webseite. Dabei zeigt Httping die Antwortzeit und den HTTP-Statuscode 200 an. Richten Sie Httping auf eine funktionierende Domain, aber eine nicht existierende Webseite, gibt das Prüfwerkzeug den klassischen 404-Fehler mit der Antwortzeit -1 aus. Gibt es schon die Domain nicht, dann leitet in unserem Beispiel der Internetanbieter auf eine eigene Navigationshilfe mit integrierter Suchfunktion weiter. Daher meldet Httping auch nicht ein “Resolving beischpiel.de failed”, sondern gibt mit 302 den entsprechenden Status-Code für die Umleitung aus.
Listing 2
#! /bin/sh echo "Diese Webseite funktioniert:" httping -g http://www.example.com -c 1 -s -m echo "-------------------------------------------------" echo "Domain vorhanden, aber Seite nicht gültig:" httping -g http://example.com/seite-gibts-nicht.html -c 1 -s -m echo "-------------------------------------------------" echo "Domain nicht vorhanden, Umleitung durch Provider:" httping -g http://beischpiel.com -c 1 -s -m
Listing 3
$ ./listing2.sh Diese Webseite funktioniert: 206,761122 200 ------------------------------------------------- Domain vorhanden, aber Seite nicht gültig: -1 404 ------------------------------------------------- Domain nicht vorhanden, Umleitung durch Provider: -1 302
Datenbanken überwachen
Neben Webservern bilden Datenbanken einen weiteren wichtigen Baustein einer IT-Infrastruktur, den es ebenfalls zu überwachen gilt. Sehr häufig kommen hier MySQL, MariaDB oder PostgreSQL zum Einsatz; auf Letzteres konzentrieren wir uns in diesem Beispiel. Zum Überwachen des Dienstes legen Sie einen eigenen Benutzer und für diesen eine Datenbank mit einer Tabelle darin an. Dadurch versetzen Sie das Shellskript in die Lage, die Abfrage automatisch vorzunehmen. Im Beispiel trägt die Datenbank den Namen waechter, in dieser findet sich die Tabelle wacht mit der Spalte zahl sowie ein Datensatz (Abbildung 2).
Der Shell-Client psql verwendet die klassischen Exitcodes 0 bei Funktion und 1 für einen Fehlschlag. Das Shellskript im Listing 4 unterscheidet nun, ob lediglich aus irgendeinem Grund die Daten nicht zugänglich sind oder der Dienst überhaupt nicht arbeitet. Abbildung 3 zeigt den Ablauf, wobei wir probehalber einmal die Daten löschten und das andere Mal den Dienst stoppten. Sofern das Skript auf dem gleichen Rechner läuft wie das relationale Datenbankmanagementsystem, können Sie auch andere Aktionen ausführen lassen.
Listing 4
#! /bin/sh
while true; do
# Datum und Zeit in Variable legen
ZEIT=$(date +%d.%m.%Y:%H:%M:%S)
# Datenbankabfrage für Exit-Code-Gewinnung
M=$(psql -q -d waechter -c "select * from wacht;")
# Exitcode speichern und auswerten
A=$?
if [ $A -eq 0 ]; then
echo "$ZEIT Datenbank arbeitet"
elif [ $A -eq 1 ]; then
echo "$ZEIT Daten nicht gefunden"
elif [ $A -eq 2 ]; then
echo "$ZEIT Datenbank inaktiv"
fi
sleep 60
done
Dienste überwachen
Zahlreiche Dienste verrichten still und leise ihre Aufgabe im Hintergrund, ohne dass sie sich wie ein Web- oder Datenbankserver direkt ansprechen ließen. Die Verfügbarkeit eines solchen Dienstes lässt sich daher nicht so einfach mit einer Abfrage überprüfen. In diesen Fällen müssen Sie darauf vertrauen, dass der Dienst bei einem aktiven Prozess auch seine Aufgabe erfüllt.
Die Abfrage des Status erfolgt anhand der Beispiele aus der Tabelle “Dienstekontrolle”. Das einfachste Werkzeug für diese Aufgabe ist das Kommando ps. Mit dem Schalter -C Prozess beschränken Sie die Suche nach dem entsprechenden Prozess auf den angegebenen Namen (Listing 5). Die von Ps gelieferten Exit-Codes lassen sich gut in Skripten weiterverarbeiten. Alternativ greifen Sie auf die Ausgaben der per service-Kommando aufgerufenen Initskripte (Listing 6) oder – bei Distributionen mit Systemd – auf systemctl (Listing 7) zurück.
Dienstekontrolle
| Methode | Aufruf | Exit-Codes |
|---|---|---|
| Prozessstatus, mit Angabe des Diensts | ps -C Prozess |
0 = existiert; 1 = existiert nicht |
Initskript mit Option status |
service Startskript status |
keine, stattdessen individuelle Meldungen |
| Abfrage mit Systemctl | systemctl status Dienst |
0 = aktiv, 3 = deaktiviert |
| Kommunikation mit dem Dienst | – | siehe Beispiele für Web- und Datenbankserver |
Listing 5
$ ps -C ntpd PID TTY TIME CMD 1054 ? 00:00:01 ntpd $ echo $? 0 # Dienst stoppen, hier via Systemd $ sudo systemctl stop ntpd.service $ ps -C ntpd PID TTY TIME CMD $ echo $? 1
Listing 6
$ service ntp status * NTP server is running $ sudo service ntp stop * Stopping NTP server ntpd [ OK ] $ service status * NTP server is not running
Listing 7
$ systemctl status ntp |- ntp.service - LSB: Start NTP daemon Loaded: loaded (/etc/init.d/ntp) Active: active (running) since Mo 2015-10-26 19:22:03 CET; 43s ago [...] $ echo $? 0 $ sudo systemctl stop ntp $ systemctl status ntp |- ntp.service - LSB: Start NTP daemon Loaded: loaded (/etc/init.d/ntp) Active: inactive (dead) since Mo 2015-10-26 19:23:04 CET; 4s ago [...] $ echo $? 3
Während Sie beim herkömmlichen SysVinit die Ausgaben des aufgerufenen Init-Skripts mit einigem Aufwand auswerten müssten, liefert der aktuelle Systemd handlichere Exit-Codes. Je nach Aufgabenstellung, Anforderungen und System kommen Sie bei der Überwachung eines Diensts mit einer der drei vorgestellten Methoden zum Ziel.
Auf Logins reagieren
Aus diesen Bausteinen realisieren Sie mit einfachen Mitteln kleine Skripte, die auf Ereignisse im System reagieren. So lassen sich beispielsweise Logins gut als Auslöser für Aktionen nutzen – etwa, um die abendlichen Diskussionen mit den Kindern zu umgehen, wenn diese zu lange am Computer sitzen. Mit dem Glockenschlag verbannen Sie sie dann, ob sie wollen oder nicht, automatisiert aus dem System.
Das Skript in Listing 8 ermittelt mithilfe von users die aktuell auf dem System angemeldeten Benutzer und filtert die Ausgabe mit grep. Damit erhalten Sie den Exit-Code 0 bei einem Treffer und 1 bei Fehlanzeige. Entsprechend des Ergebnisses und der aktuellen Zeit (untersagt sind die Stunden zwischen 21 und 7 Uhr) lässt das Skript den User simon im System oder wirft ihn kurzerhand hinaus (Abbildung 4).
Listing 8
#! /bin/sh
while true; do
# Aktuelle Stunde ermitteln
STUNDE=$(date +%H)
# Ist Simon angemeldet?
users | grep -q simon
# Exitcode auswerten
A=$?
if [ $A -eq 0 ]; then
# Simon ist angemeldet
if [ $STUNDE -le 7 ] || [ $STUNDE -ge 21 ]; then
# vor 7 bzw. nach 21 Uhr
killall -u simon
fi
fi
sleep 60
done
Das Prinzip lässt sich auf Komfort- und Automatisierungsfunktionen übertragen. So starten Sie etwa mit einem leicht abgewandelten Skript (Listing 9) einen Webserver, sobald sich ein bestimmter Nutzer (im Beispiel jefe) anmeldet. In diesem Fall ist das Skript für den Einsatz auf einem Systemd-System abgestimmt, eventuell müssen Sie auch den Namen des Webserver-Diensts (im Beispiel httpd.service) anpassen.
Listing 9
#! /bin/sh
while true; do
# Ist jefe angemeldet?
users | grep -q jefe
# Exitcode auswerten
A=$?
if [ $A -eq 0 ]; then
# jefe angemeldet
# Status des Webservers prüfen
systemctl status httpd.service
# Exitcode auswerten
B=$?
# Webserver bei Bedarf starten
if [ $B -gt 0 ]; then
systemctl start httpd.service
fi
else
# jefe nicht angemeldet
# Status des Webservers prüfen
systemctl status httpd.service
# Exitcode auswerten
C=$?
if [ $C -eq 0 ]; then
# Webserver bei Bedarf beenden
systemctl stop httpd.service
fi
fi
sleep 60
done
Der Nutzer muss keine Kommandos eingeben oder Aktionen starten. Dabei müssen Sie nicht einmal Änderungen an den Home-Verzeichnissen der Benutzer vornehmen etwa in der ~/.profile oder ~/.bashrc) – es genügt eine aktive Sitzung. Mit diesem Vorgehen übertragen Sie wichtige Aufgaben, wie etwa den Start eines Diensts oder einer Datensicherung, auf unprivilegierte Benutzer. Dafür müssen Sie das Shellskript jedoch noch beim Hochfahren des Rechners automatisch aufrufen. Dabei gehen Sie je nach Init-System unterschiedlich vor.
Generell legen Sie das ausführbare Shellskript im Verzeichnis /usr/local/sbin ab. Bei älteren Systemen wie Debian 7 mit SysVinit kopieren Sie unter /etc/init.d die meist vorinstallierte Vorlage skeleton in eine neue Datei mit passendem Namen – im Beispiel webanmeldung. Anschließend bearbeiten Sie das Init-Skript nach Ihren Vorstellungen, speichern die Änderungen ab und machen die Datei mit chmod +x ausführbar. Mit update-rc.d webmeldung defaults aktivieren Sie sie für die üblichen Runlevel.
Arbeiten Sie auf einem Rechner mit Systemd, legen Sie entsprechend Listing 10 unter dem eventuell neu anzulegenden Verzeichnis /usr/local/lib/systemd/system eine neue Unit-Datei mit dem Namen webmeldung.service an und führen die Anweisungen aus Listing 11 aus. Diese verlinken die Anweisung im System und sorgen beim Booten für einen automatischen Start.
Listing 10
[Unit] Description=Start Webserver bei Anmeldung jefe Documentation=man:users(1) [Service] ExecStart=/usr/local/sbin/webmeldung.sh IgnoreSIGPIPE=false [Install] WantedBy=multi-user.target
Listing 11
$ sudo systemctl enable webmeldung.service Created symlink from /etc/systemd/system/multi-user.target.wants/webmeldung.service to /usr/local/lib/systemd/system/webmeldung.service. $ sudo systemctl start webmeldung.service $ sudo systemctl status webmeldung.service * webmeldung.service - Start Webserver bei Anmeldung jefe Loaded: loaded (/usr/local/lib/systemd/system/webmeldung.service; enabled; vendor preset: disabled) Active: active (running) since Di 2015-10-27 14:16:13 CET; 6s ago [...]
Meldungen per E-Mail
Optional lassen Sie sich über wichtige Ereignisse per E-Mail informieren. Dafür benötigen Sie einen Mail-Transport-Agent (MTA) wie etwa Ssmtp [1] auf dem Rechner. Er leitet E-Mails über einen regulären SMTP-Server weiter, sodass die Server-Mails nicht gleich vom empfangenden E-Mail-Dienst als Spam aussortiert werden.
Im Listing 12 finden Sie ein einfaches Shellskript, das Sie über alle um 22 Uhr noch angemeldeten Benutzer per E-Mail informiert. Das Skript erstellt für diese Aufgabe die Hilfsdatei mail.txt, die ssmtp dann als Eingabe für die zu versendende E-Mail nutzt.
Listing 12
#!/bin/sh
EMPFAENGERADRESSE=papa@beispiel.com
ABSENDERADRESSE=kinderzimmer@heim.netz
while true; do
stunde=$(date +%H)
if [ $stunde -eq 22 ]; then
echo "To: $EMPFAENGERADRESSE" > mail.txt
echo "From: $ABSENDERADRESSE" >> mail.txt
echo "Subject: Benutzerabfrage" >> mail.txt
echo "" >> mail.txt
users >> mail.txt
ssmtp $EMPFAENGERADRESSE < mail.txt
sleep 15
#sleep 3600
fi
done
Vor dem Start des Skripts müssen Sie Ssmtp jedoch noch einrichten. Dies geschieht über die Konfigurationsdateien ssmtp.conf (Listing 13) und revaliases (Listing 14) aus dem Verzeichnis /etc/ssmtp. Je nachdem, welchen E-Mail-Anbieter Sie ansprechen möchten, müssen Sie an dieser Stelle unterschiedliche Konfigurationen eintragen. Haben Sie Schwierigkeiten, die richtigen Angaben zu finden, hilft in der Regel eine Internetrecherche mit den Begriffen “Provider ssmtp” weiter.
Listing 13
root=papa@beispiel.com mailhub=smtp.beispiel.com:25 hostname=Kinderzimmer UseTLS=Yes UseSTARTTLS=YES AuthUser=Login für SMTP-Server AuthPass=Passwort für SMTP-Server FromLineOverride=NO
Listing 14
root:papa@beispiel.com:smtp.beispiel.com:25
Die Beispiele in den Konfigurationsdateien beziehen sich auf einen normalen Freemail-Anbieter. Zu Testzwecken versehen Sie den Aufruf von ssmtp im Shellskript mit der Option -v. Das Programm gibt sich so deutlich auskunftsfreudiger, sodass Sie Fehler bei der Übertragung schnell erkennen und die notwendigen Anpassungen vornehmen können.
Sicherheit
Achten Sie darauf, dass sich die Ssmtp-Konfigurationsdatei nur von Root oder demjenigen Benutzer einsehen lässt, in dessen Kontext Ssmtp ausgeführt wird. Entsprechende Hinweise zur Konfiguration liefert die Dokumentation der genutzten Linux-Distribution, wie zum Beispiel das Wiki von Arch Linux [2].
Ausblick
Die hier gezeigten Beispiele bilden nur einen Bruchteil der Möglichkeiten ab. Zum Erstellen von Skripten benötigen Sie keine großen Programmierkenntnisse, Erfahrungen mit Terminalanwendungen und einfachen Konstrukten wie While-Schleifen und If-Unterscheidungen genügen in der Regel.
Der Autor
Harald Zisler beschäftigt sich seit den frühen 90er-Jahren mit FreeBSD und Linux. Er verfasst Artikel und Bücher zu Technik- und EDV-Themen. Kürzlich erschien die dritte Auflage seines Buchs “Computer-Netzwerke” beim Rheinwerk Verlag. Rund um den Themenbereich Linux und Datenbanken führt er auch Kleingruppenkurse durch.
Infos
[1] Ssmtp: https://packages.qa.debian.org/s/ssmtp.html
[2] Ssmtp-Sicherheit: https://wiki.archlinux.org/index.php/SSMTP#Security









