Translations of this page:

Nagios optimal konfigurieren

logo_nagios Um in hochkomplexen Monitoring-Umgebungen mittels Nagios die noetigen Anpassungen, wie beispielsweise dem Hinzufuegen von weiteren Servern oder Abaendern von bestehenden Konfigurationen, zeitlich moeglichst gering zu halten, ist eine feste, intelligente Struktur in der Konfiguration absolut unabdingbar. Monitoring ist schließlich dazu da, Fehlerlokalisation zu erleichtern, vielleicht gar zu automatisieren und somit freie Zeitraeume fuer andere wichtige Tasks zu schaffen und eben nicht dazu, die freie Zeit damit zu verbringen, die Monitoring-Umgebung staendig pflegen zu muessen.
Nagios bringt von Hause aus nuetzliche, objektorientierte Prinzipien mit, die man sich in großen, wachsenden Umgebungen zunutze machen muss.

Viele Systemadministratoren machen sich zu Beginn leider nicht die Muehe, genauer zu planen, was denn eigentlich ueberwacht werden soll oder welche Moeglichkeiten sich bei der Konfiguration ergeben. Das hat zur Folge, dass die Installation, die eigentlich zum Evaluieren gedacht war, spaeter auch produktiv eingesetzt wird und die vielen, kleinen Fehler, die man zu Beginn unweigerlich macht, in den produktiven Einsatz mit hinuebergefuehrt werden. Spaeter, wenn die Monitoring-Umgebung waechst, werden diese kleinen, unueberlegten Fehler meist zu einer zeitraubenden Angelegenheit, die aufgrund der Komplexitaet der Konfiguration auch nicht mehr ohne grossen Zeitaufwand zu beheben sind.

Ein Beispiel:

Die Nagios-Installation funktioniert. Man moechte nun einen ersten Host hinzufuegen. Der gemeine Administrator lernt also, wie man einen Host und dazu gehoerige Services definiert. In der Konfiguration sieht das dann meistens so aus:

hosts.cfg

define host{
	host_name			webserver-123
	alias				Webserver 123
	address				192.168.1.42
	parents				switch-456
	check_command			check-host-alive
	check_interval			5
	retry_interval			1
	max_check_attempts		5
	check_period			24x7
	process_perf_data		0
	retain_nonstatus_information	0
	contact_groups			webserver-admins
	notification_interval		30
	notification_period		24x7
	notification_options		d,u,r
	}
 
define service{
	host_name		webserver-123
	service_description	HTTP
	check_command		check-http!80
	max_check_attempts	5
	check_interval	5
	retry_interval	3
	check_period		24x7
	notification_interval	30
	notification_period	24x7
	notification_options	w,c,r
	contact_groups		webserver-admins
	}


Wir sehen hier also den Host ‘webserver-123′ und den dazugehoerigen Service ‘HTTP’, der ueberprueft, ob der Webserver denn auch auf localhost:80 lauscht. Soweit so gut: 31 Zeilen Konfiguration lassen sich noch recht gut ueberschauen und im Zweifelsfall auch anpassen. Nun ist es aber nicht mit dem Ueberwachen eines einzigen Services erledigt. Neben dem Ueberpruefen, ob HTTP funktioniert sind vielleicht auch noch andere Informationen nuetzlich, wie beispielsweise die Auslastung der CPU oder RAM, dem freien Speicherplatz auf den HDDs, dem Load der Maschine, wieviele Prozesse am laufen sind, die Anzahl der eigenloggten User, dem Datendurchsatz auf den einzelnen Interfaces und vieles, vieles mehr.
700-1000 Zeilen pro zu ueberwachendem Host in der Konfiguration werden ohne grosse Probleme erreicht (inklusive dem Aerger, den man spaeter hat aufgrund des Zeitaufwands, den man einplanen muss, wenn Anpassungen anstehen). Dafuer gibt es jedoch eine Loesung.

Am Anfang war das Template

Nagios folgt einem strikt objektorientierten Ansatz. Man hat also die Moeglichkeit einen (oder auch mehrere) generische Templates zu definieren, von dem die tatsaechlich zu ueberwachenden Hosts und Services ihre Einstellungen erben. Man lagert also alle Optionen in das generische Template aus und definiert den jeweiligen Host oder Service nur mit den Optionen, die auch wirklich fuer die spezifische Maschine notwendig sind. Zuerst folgt die Definition des Templates, danach die des Hosts.

templates.cfg

define host{
        name                            generic-host    ; The name of this host template
        notifications_enabled           1               ; Host notifications are enabled
        event_handler_enabled           1               ; Host event handler is enabled
        flap_detection_enabled          1               ; Flap detection is enabled
        failure_prediction_enabled      1               ; Failure prediction is enabled
        process_perf_data               1               ; Process performance data
        retain_status_information       1               ; Retain status information across program restarts
        retain_nonstatus_information    1               ; Retain non-status information across program restarts
	check_period			24x7		; By default, Linux hosts are checked round the clock
	check_interval			5		; Actively check the host every 5 minutes
	retry_interval			1		; Schedule host check retries at 1 minute intervals
	max_check_attempts		3		; Check each Linux host 10 times (max)
        check_command           	check-host-alive ; Default command to check Linux hosts
	notification_period		24x7		; Linux admins hate to be woken up, so we only notify during the day
							; Note that the notification_period variable is being overridden from
							; the value that is inherited from the generic-host template!
	notification_interval		30		; Resend notifications every 2 hours
	notification_options		d,u,r		; Only send notifications for specific host states
	contact_groups			nagios-admins	; Notifications get sent to the admins by default
        register                        0               ; DONT REGISTER THIS DEFINITION - ITS NOT A REAL HOST, JUST A TEMPLATE!
        }

hosts.cfg

define host{
        use                     generic-host
        host_name               webserver-01
        alias                   Webserver 01
        address                 192.168.1.42
        }


Die Anzahl der Konfigurationsparameter fuer einen einzelnen Host ist somit von 17 auf 6 Zeilen reduziert worden. Das gleiche Prinzip laesst sich natuerlich auch auf Services anwenden:

templates.cfg

define service{
        name                            generic-service 	; The 'name' of this service template
        active_checks_enabled           1       		; Active service checks are enabled
        passive_checks_enabled          1    		   	; Passive service checks are enabled/accepted
        parallelize_check               1       		; Active service checks should be parallelized (disabling this can lead to major performance problems)
        obsess_over_service             1       		; We should obsess over this service (if necessary)
        check_freshness                 0       		; Default is to NOT check service 'freshness'
        notifications_enabled           1       		; Service notifications are enabled
        event_handler_enabled           1       		; Service event handler is enabled
        flap_detection_enabled          1       		; Flap detection is enabled
        failure_prediction_enabled      1       		; Failure prediction is enabled
        process_perf_data               0       		; Process performance data
        retain_status_information       1       		; Retain status information across program restarts
        retain_nonstatus_information    1       		; Retain non-status information across program restarts
        is_volatile                     0       		; The service is not volatile
        check_period                    24x7			; The service can be checked at any time of the day
        max_check_attempts              3			; Re-check the service up to 3 times in order to determine its final (hard) state
        normal_check_interval           5			; Check the service every 10 minutes under normal conditions
        retry_check_interval            1			; Re-check the service every two minutes until a hard state can be determined
        contact_groups                  nagios-admins		; Notifications get sent out to everyone in the 'admins' group
	notification_options		c,r			; Send notifications about warning, unknown, critical, and recovery events
        notification_interval           20			; Re-notify about service problems every hour
        notification_period             24x7			; Notifications can be sent out at any time
        register                        0       		; DONT REGISTER THIS DEFINITION - ITS NOT A REAL SERVICE, JUST A TEMPLATE!
        }

services.cfg

define service{
        use                     generic-service
        service_description     HTTP
        check_command           check_http!80
        host_name               webserver-01
        }


Der Vorteil liegt auf der Hand: Nehmen wir an, die IT-Abteilung ist gewachsen und es wurden einzelne Teams fuer spezifische Server eingeteilt. Jetzt haben wir also nicht mehr nur die Kontaktgruppe “nagios-admin”, sondern auch die Gruppe “webserver-admin”. Der objektorientierte Ansatz macht mir die Aenderungen leicht, indem ich die Kontaktgruppe lediglich in der Template-Definition hinzufuege und eben nicht in jeder einzelnen Host- und Service-Definition. Grade fuer Administratoren, die mit awk und sed (unverstaendlicherweise) auf Kriegsfuss stehen, ist Letzteres eine enorm zeitaufwendige Arbeit, die man sich so ersparen kann.
Jetzt ist die Monitoring-Umgebung also gewachsen. Wir ueberwachen eine Vielzahl verschiedenster Dienste und wurden letzte Nacht aufgrund einer Warnung, dass sich der Disk Space auf /dev/sda3 verringert, nachts um halb 4 aus dem Bett geklingelt. Das Problem ist nun nicht derart unternehmenskritisch, als das wir dafuer unseren wohlverdienten Schlaf unterbrechen muessten und koennte auch problemlos morgens um 9 vom Office aus behoben werden. In unserer generischen Service-Definition, unserem Template, haben wir jedoch eine 24×7 Benachrichtung definiert. Wir muessen uns also ueberlegen, wie wir erreichen koennen, das fuer einzelne Checks andere Bedingungen gelten. Dafuer bieten sich folgende zwei Loesungen an:

Ueberschreiben von Template-Definitionen


Wir erinnern uns: In unserem Service-Template haben wir folgendes definiert:

templates.cfg

        notification_period             24x7			; Notifications can be sent out at any time


Dies gilt fuer alle Services, die ihre Optionen von diesem Template erben. Um die Option des Templates zu ueberschreiben, koennen wir in der spezifischen Service-Definition die jeweilige Option wie folgt ueberschreiben:

services.cfg

define service{
        use                     generic-service
        service_description     DISK3
        check_command           check_nrpe!5667!check_disk3
        host_name               webserver-01
        notification_period     8x5
        }


Wir haetten somit unser Ziel erreicht und wuerden bezueglich etwaigiger Speicherplatz-Probleme nur noch waehrend der Arbeitszeit benachrichtigt werden. Allerdings ist diese Art und Weise eher eine “von hinten durch die Brust ins Auge”-Loesung. Wir haben schließlich wieder die Service Definition aufgeblaeht und was passiert, wenn wir weitere Optionen aus dem Service-Template veraendern moechten? Richtig, die Konfiguration von spezifischen Hosts und Services waechst wieder auf ein unertraegliches, wartungsfeindliches Mass an. Problematisch ist jetzt nicht mehr nur der Zeitaufwand, sondern auch das uneinheitliche Bild in der Konfiguration. Man muss schlicht und ergreifend wissen, dass man die notification_period fuer den Check in der Service-Definition explizit veraendert hat.
Wuerde beispielsweise beschlossen werden, dass /dev/sda3 jetzt doch eher zu den unternehmenskritischen Diensten gehoert und unter keinen Umstaenden in Platznoete geraten darf, dann steht dem Administrator, der schon lange oder gar noch nie nichts mehr an der Konfiguration gemacht hat, zuerst einmal eine laengere Suche nach der Option im Heuhaufen bevor. Besser ist es daher, sich mehrere Service-Templates fuer einzelne Service-Kategorien zu erstellen und diese vom generischen Template erben zu lassen. Man kann also auch Templates von anderen Templates erben lassen.

Vererbung innerhalb von Templates

Bevor man damit beginnt, eine Vielzahl von verschiedenen Service-Templates zu erstellen, sollte man konsolidieren. Ich beispielsweise fahre sehr gut mit nur 4 weiteren Service-Templates, die allesamt verschiedene Gewichtungen beinhalten bezueglich der Intervalle, in denen der jeweilige Dienst ueberprueft wird und den Zeitraeumen, in denen dies geschehen soll und ihre Einstellungen vom oben beschriebenen Service-Template erben:

templates.cfg

define service{
	name				normal-service	; The name of this service template
	use				generic-service		; Inherit default values from the generic-service definition
        max_check_attempts              3			; Re-check the service up to 4 times in order to determine its final (hard) state
        normal_check_interval           5			; Check the service every 5 minutes under normal conditions
        retry_check_interval            1			; Re-check the service every minute until a hard state can be determined
        register                        0       		; DONT REGISTER THIS DEFINITION - ITS NOT A REAL SERVICE, JUST A TEMPLATE!
	}
 
define service{
	name				important-service	; The name of this service template
	use				generic-service		; Inherit default values from the generic-service definition
        max_check_attempts              2			; Re-check the service up to 4 times in order to determine its final (hard) state
        normal_check_interval           1			; Check the service every 5 minutes under normal conditions
        retry_check_interval            1			; Re-check the service every minute until a hard state can be determined
        register                        0       		; DONT REGISTER THIS DEFINITION - ITS NOT A REAL SERVICE, JUST A TEMPLATE!
	}
 
define service{
	name				minor-service		; The name of this service template
	use				generic-service		; Inherit default values from the generic-service definition
        max_check_attempts              5			; Re-check the service up to 4 times in order to determine its final (hard) state
        normal_check_interval           10			; Check the service every 5 minutes under normal conditions
        retry_check_interval            5			; Re-check the service every minute until a hard state can be determined
        notification_period             24x7			; Notifications can be sent out at any time
        register                        0       		; DONT REGISTER THIS DEFINITION - ITS NOT A REAL SERVICE, JUST A TEMPLATE!
	}
 
define service{
	name				unimportant-service	; The name of this service template
	use				generic-service		; Inherit default values from the generic-service definition
        max_check_attempts              10			; Re-check the service up to 4 times in order to determine its final (hard) state
        normal_check_interval           60			; Check the service every 5 minutes under normal conditions
        retry_check_interval            10			; Re-check the service every minute until a hard state can be determined
        notifications_enabled           0       		; Service notifications are disabled
        register                        0       		; DONT REGISTER THIS DEFINITION - ITS NOT A REAL SERVICE, JUST A TEMPLATE!
	}


Man ist somit also problemlos in der Lage, bestimmte Services im Gegensatz zu anderen weniger zu gewichten. Wichtige, unternehmenskritische Dienste koennen im Minutenintervall ueberprueft werden, andere weniger wichtigere Dienste aber beispielsweise nur stuendlich. Wir erreichen somit die noetige Flexibilitaet, um Dienste entsprechend ihrer Bedeutung ueberpruefen zu koennen.

Hosts zu Hostgruppen zusammenfassen

Nun haben wir eine bereits sehr gute Basis erreicht. Wir sind in der Lage, Hosts und Services mittels einiger, weniger Zeilen in der Konfiguration anzulegen und abzuaendern. Allerdings muessen wir weiterhin fuer jeden Host die Services einzeln anlegen, was zur Folge hat, dass fuer die 6 Zeilen lange Host-Definition etwa 100 Zeilen Service-Definition folgen. Hier gilt es zu optimieren, indem wir zuerst einmal Hostgruppen nach folgendem Schema einrichten:

hostgroups.cfg

define hostgroup{
	hostgroup_name			webserver
	alias				Our company's webserver
	members				webserver-01,webserver-02,webserver-03
	}

Hostgruppen-basierte Service-Definitionen

Der Weg zu Hostgruppen-basierten Services ist jetzt nicht mehr weit. Anstatt den HTTP Service-Check fuer jeden einzelnen Host mittels des Hostnames definieren, nehmen wir jetzt einfach den Namen der Hostgruppe. Das sieht dann wie folgt aus:

define service{
        use                     important-service
        service_description     HTTP
        check_command           check_http!80
        hostgroup_name          webserver
        }


Anstatt jeden einzelnen Service fuer die entsprechenden Hosts konfigurieren zu muessen, koennen wir mit Hilfe der Hostgruppen die Service-Definitionen global abhandeln. Wir haben jetzt also nur noch eine Service-Definition anstatt eine fuer jeden Host!
Das hat nicht nur den Vorteil, dass man mit geringem Zeitaufwand die komplette Installation pflegen kann, sondern auch, dass einem der Ueberblick ueber die Umgebung nicht so leicht entgleitet. Mehrere hundert Hosts und tausende Services sind in einer hochkomplexen Umgebung keine Seltenheit, da ist Vereinheitlichung schlicht und ergreifend eine Notwendigkeit.

Performancegrenzen ausloten

Abschließend noch ein, zwei Worte zur Performance von Nagios. Diese laesst sich, wer haette es geahnt, nicht so einfach in Zahlen ausdruecken. Eine Aussage, wie beispielsweise “Nagios kann 831 Hosts und 5.542 Services zeitnah ueberwachen” ist schlicht und ergreifend nicht moeglich. Zu komplex sind die Abhaengigkeiten von der Hardware, der Art und Anzahl der eingesetzten Checks, sowie der Intervalle, in denen die Dienste ueberprueft werden. Muss Nagios nach jedem Check noch ein externes Kommando aufrufen, sind weitere Verzoegerungen in Kauf zu nehmen.
Nun ist der gemeine Nagios-Administrator meist von der Idee angefixt, moeglichst alles zu ueberwachen: Laeuft der syslog-ng auf all meinen Servern? Kann ich den Hostnamen auf all meinen 10 eingesetzten Nameservern aufloesen? Und wann ist eigentlich mal wieder Towel-Day?
Nun spiegelt der Load des Nagios-Servers die Performance meist nur unzureichend wieder. Akkurate Aussagen lassen sich mittels des Load-Wertes jedenfalls nicht machen. Vielleicht laeuft ja auch noch ein anderer, performancekritischer Dienst auf der Maschine. Einen ersten Blick sollte man also ins Web-Interface werfen und sich die Performance-Werte zu Gemuete fuehren:

Interessant sind hier zuerst einmal die Werte “Check Latency - Maximum” und “Check Latency - Average” fuer unsere Services. Diese Werte spiegeln die Zeit wieder, wie lange ein auszufuehrender Check in der Warteschlage von Nagios verzoegert wird. Wenn ich also einen Check habe, der alle fuenf Minuten ueberprueft werden soll und eine durchschnittliche Check Latency von ca. zehn Sekunden besteht, dann wird dieser Check eben erst wieder nach fuenf Minuten und zehn Sekunden ausgefuehrt.
Ein weiterer, guter Indikator fuer Performanceprobleme ist die Tabelle auf der linken Seite, die angibt, wieviele Checks der Nagios-Server in einer, in fuenf in 15 Minuten, sowie in einer Stunde ausfuehren konnte.
In grossen Installation wird es aufgrund der Masse an Checks, sowie der Vielzahl von verschiedenen Plugins kaum dazu kommen, eine Latenz im Millisekundenbereich zu erreichen. Zu Beginn jedoch mit wenigen hundert Services sollte dieser Wert sich entsprechend dort ansiedeln.

Performance-Monitoring

Eine weitere Moeglichkeit, Performancegrenzen von Nagios auszumachen ist das Monitoring des eigenen Nagios-Servers. Ich beispielsweise setze dazu ein kleines Bash-Script von Matteo Corti als Check ein, welches mir alle 10 Minuten die Check Latency inklusive Performancedaten zurueckgibt. Ich bin also in der Lage, diese grafisch ueber laengere Zeitraeume darzustellen, beispielsweise mittels PNP oder Nagiosgrapher und kann somit beim Einbinden neuer Checks auch leicht zeitversetzt Performance-Engpaesse ausmachen und diese ggf. beheben. Grad umfangreiche Bash-Scripte versetzten Nagios eine ungemein laestige Performancebremse. Ein Plugin in C oder Perl ist Shellscripts meist vorzuziehen.

Anhang: Performance-Monitoring Shellscript

Hier das Performance-Monitoring Shellscript zum Ueberwachen der Latenz von Matteo Corti, welches u.a. auch auf Nagiosexchange zum Download angeboten wird:

#!/bin/bash\\ 
# (c) Matteo Corti, ETH Zurich, 2007
#
# check_nagios_latency
#
# Checks the Nagios latency
 
VERSION=0.9.3
 
################################################################################
# Functions
 
################################################################################
# Prints usage information
# Params
#   $1 error message (optional)
usage() {
 
    if [ -n "$1" ] ; then
        echo "Error: $1" 1>&2
    fi
 
    echo
    echo "Usage: check_nagios_latency [-hvV?] -w warning -c critical [-n path]"
    echo
    echo "   -c         critical threshold"
    echo "   -h, -?     this help message"
    echo "   -n path    nagiostats path"
    echo "   -v         verbose output"
    echo "   -w         warning threshold"
    echo "   -V         version"
    echo
    echo "Report bugs to: Matteo Corti <matteo.corti@id.ethz.ch>"
    echo
 
    exit 3
 
}
 
################################################################################
# Checks if a given program is available and executable
# Params
#   $1 program name
check_prog() {
 
    if [ -z "$PROG" ] ; then
        PROG=`which $1`
    fi
 
    if [ -z "$PROG" ] ; then
        echo "LATENCY CRITICAL - cannot find $1"
        exit 2
    fi
 
    if [ ! -x "$PROG" ] ; then
        echo "LATENCY CRICTICAL - $PROG is not executable"
        exit 2
    fi
 
}
 
################################################################################
# Main
################################################################################
 
# process command line options
while getopts "vh?Vc:w:n:" opt; do
    case $opt in
        c )      CRITICAL=$OPTARG;  ;;
        h | \? ) usage ; exit 3;    ;;
        n )      PROG=$OPTARG ;;
        V )      echo "check_nagios_latency version ${VERSION}"; exit 3; ;;
        v )      VERBOSE=1;         ;;
        w )      WARNING=$OPTARG;   ;;
    esac
done
shift $(($OPTIND - 1))
 
################################################################################
# sanity checks
 
###############
# Check options
if [ -z "${CRITICAL}" ] ; then
    usage "No critical threshold specified"
fi
if [ -z "${WARNING}" ] ; then
    usage "No warning threshold specified"
fi
 
######################
# Check number formats
 
if ! echo $WARNING | grep -qE '^[0-9]+(\.[0-9]+)?$' ; then
    echo "LATENCY UNKOWN - Wrong number: $WARNING"
    exit 3
fi
 
if ! echo $CRITICAL | grep -qE '^[0-9]+(\.[0-9]+)?$' ; then
    echo "LATENCY UNKOWN - Wrong number: $WARNING"
    exit 3
fi
 
#######################
# Check needed programs
 
check_prog nagiostats
 
LATENCY=`$PROG | grep "Active Service Latency" |cut -f3 -d'/' | awk '{print $1}' | tr -d '\n'`;
 
if [ -n "${VERBOSE}" ] ; then echo "latency: ${LATENCY}"; fi
 
####################
# Perform the checks
 
PERF="Latency=${LATENCY};${WARNING};${CRITICAL};;"
 
COMPARISON=`echo "if($LATENCY>$CRITICAL) 1 else 0;" | bc`
if [ $COMPARISON -eq 1 ] ; then
    echo "LATENCY CRITICAL ${LATENCY}s | $PERF"
    exit 2
fi
 
COMPARISON=`echo "if($LATENCY>$WARNING) 1 else 0;" | bc`
if [ $COMPARISON -eq 1 ] ; then
    echo "LATENCY WARNING ${LATENCY}s | $PERF"
    exit 1
fi
 
echo "LATENCY OK ${LATENCY}s| $PERF"
exit 0;

Rechtliches

Dieser Beitrag ist unter einer Creative-Commons Lizenz veroeffentlicht worden. Er darf frei kopiert, veroeffentlicht und veraendert werden, sofern der Name des Autors (Mike Adolphs) genannt wird und keine kommerziellen Absichten verfolgt werden (Google AdSense in Blogs, Foren und Wikis ausgenommen). Ueber Feedback freut sich der Autor genauso, wie ueber Verbesserungsvorschlaege und Benachrichtigungen im Falle von offensichtlichen Fehlern.

nagios/tips/nagios_optimal_konfigurieren.txt · Zuletzt geändert: 2009/03/19 09:58 von scha
CC Attribution-Noncommercial-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0