Check_MK: MRPE-Optimierung durch Intervall bezogene Checks [UPDATE]
30. April 2013 | Von Thorsten Robers | Kategorie: Monitoring | AvailabilityDer Einsatz von Check_MK bietet viele Vorteile: automatische Inventarisierung der zu überwachenden Systeme, mitgelieferte Templates für PNP4Nagios, eine Vielzahl an vorgefertigten Checks … Du findest weitere Informationen zum Einsatz von Check_MK in verschiedenen Artikeln auf diesem Blog oder auf der Seites des Check_MK-Projektes.
In diesem Artikel soll es um die Möglichkeiten gehen die Ausführung von Nagios-Plugins auf dem lokalen System flexibler zu gestalten. Bei allen Vorteilen die Check_MK bietet hat es aber auch einen entscheidenen Nachteil. Es gibt nur ein Zeitintervall in dem immer alle Checks ausgeführt werden müssen. Per Voreinstellung werden alle Checks im Abstand einer Minute durchgeführt. Bei einem Kunden hatten wir jedoch das Problem, dass er mehrer lokalen Checks durchführen musste. Dies hatte jedoch negative Auswirkungen auf die Latenzzeiten der Check-Ausführungen insgesamt.
Bei diesem Kunden dauerte die Ausführung einer Prüfung mittels Check_MK rund 15 Sekunden.
$ check_mk -nv kvm2 Check_mk version 1.1.8b3 CPU load OK - 15min Load 0.00 at 4 CPUs CPU utilization OK - user: 0.4%, system: 0.3%, wait: 0.0% ... sg10 OK: no SMART errors detected sg11 OK: no SMART errors detected sg12 OK: no SMART errors detected sg4 OK: no SMART errors detected sg5 OK: no SMART errors detected sg6 OK: no SMART errors detected sg9 OK: no SMART errors detected OK - Agent Version 1.1.8b3, processed 39 host infos in 15.1 sec|execution_time=15.052
Die lange Ausführungszeit resultierte aus den Checks, die durch den Einsatz von MRPE ausgeführt wurden. Hierbei werden reguläre Nagios-Plugins in der Datei /etc/check_mk/mrpe.cfg konfiguriert und bei der Abfrage von Check_MK auch jedesmal ausgeführt. Nun ist das Problem, dass dies jedoch im Abstand von einer Minute geschieht.
Für den Kunden ist dieses Zeitintervall für einge seiner Checks jedoch völlig überdimensioniert. So würde ein Test auf Festplattenfehler mit den smartmontools auch im Abstand einer Stunde ausreichen. Nun gab es zunächst die Überlegung neben Check_MK auch den Nagios Remote Plugin Executor (NRPE) einzusetzen. Dies wurde jedoch schnell wieder verworfen, weil es zum einen auf dem zu überwachenden System einen zusätzlichen Daemon erfordert hätte, als auch eine separate Konfiguration und Überwachung eines dieses Daemon. Der Kunde wünschte sich aber auch die Möglichkeit einer automatischen Inventarisierung von Systemen, was zumindest beim Einsatz von NRPE nicht möglich ist. Also war die Frage geklärt und es musste eine Lösung auf der Basis von Check_MK gefunden werden.
Die Lösung dieses Problem war dann jedoch gar nicht so kompliziert. Zunächst stand die Überlegung an, die Ausführung der Checks von der Ausführung des check_mk_agent zu entkoppeln, aber dennoch über diesen die Checkergebnisse an die Nagios- oder Icinga-Instanz zu übergeben. Die Entkoppelung war schnell gelöst, dazu wird der Crond für die zeitgesteuerte Ausführung verwendet. Da wir uns auf die Zeitintervalle hourly, daily und weekly beschränkt haben musste in die entsprechenden /etc/cron.*/-Verzeichnisse zunächst ein Skript hinterlegt werden, welches sich um die Ausführung der Plugins kümmert.
# cat /etc/cron.hourly/check_mk_hourly.sh #!/bin/bash # Ausfuehren der stuendlichen Checks FILES=/etc/check_mk/hourly/* for f in $FILES do $f done
Die stündlichen Checks werden nun durch den Cron-Daemon ausgeführt. Dieser führt in den entsprechenden Intervallen alle ausführbaren Skripte im Verzeichnis /etc/check_mk/hourly/ aus. Angepasste Skripte gibt es dann auch in den Verzeichnissen /etc/crond.daily/ und /etc/cron.weekly/. Damit wir diese Checkergebnisse auch per Check_MK an das Monitoring-System übertragen können, wenden wir einen Trick an.
Schauen wir uns hierzu zunächst eines der Skripte an, die im Rahmen des Cron-Job ausgeführt werden.
#!/bin/bash # Auszufuehrendes Plugin CMD="/usr/local/libexec/nagios-plugins/check_smart -d /dev/sg12 -i scsi" # Plugin-Beschreibung DESCR="sg12" #Ausfuehrungsintervall: hourly, daily, weekly INTERVAL=hourly # Ab hier nicht mehr editieren! TEMPFILENAME=$(date +%s) MV=$(which mv) PLUGIN=${CMD%% *} OUTPUT=$(eval "$CMD") echo "(${PLUGIN##*/}) $DESCR $? $OUTPUT" > /tmp/check_mk/$TEMPFILENAME.$DESCR $MV -f /tmp/check_mk/$TEMPFILENAME.$DESCR /tmp/check_mk/$INTERVAL/$DESCR.mk
Was macht dieses Skript? Zunächst definieren wir in der Variablen CMD den konkreten Aufruf des Nagios-Plugins mit allen Parametern, die für dieses Plugin erforderlich sind. In der Variable DESCR hinterlegen wir die Beschreibung, wie dieser Check später inventarisiert werden soll und wie er anschließend im Nagios benannt wird. Zusätzlich definieren wir in einer Variablen den Interval, in dem das Plugin ausgeführt werden soll. Wofür die letzte Variable notwendig ist erkläre ich später.
Auf die Definition der drei Variablen wird im wesentlichen das Plugin ausgeführt und die Ausgabe in eine temporäre Datei gespeichert. Abschließend wir die Temporäre Datei noch in eine Datei mit der Bezeichung des Checks verschoben. Die Ausgabe erfolgt in einer Form, in der sie auch bei einer direkten Ausführung durch MRPE präsentiert würde.
(check_smart) sg4 0 OK: no SMART errors detected|defect_list=0 temperature=20;;65
Der Aufbau der Ausgabe folgt einem bestimmten Muster: geklammert wird zunächst das ausgeführte Nagios-Plugin ausgegeben – diese Information ist für die spätere Auswahl eines PNP4Nagios-Templates erforderlich. Darauf folgt die service_description, mit dem der Check eine bestimmte Bezeichnung erhält. Daran schließt sich der Rückgabe-Wert der Plugin-Ausführung an, hieran erkennt Nagios später, den Zustand des Checks. Und abschließend wird der normale Output des Plugins angehangen.
Durch die Zwischenspeicherung in eine temporäre Datei und anschließendes verschiebenes dieser Datei soll eine Racecondition verhindert werden, wenn später der check_mk_agent und das Skript, welches das Plugin aufruft, zeitgleich auf die Datei zugreifen sollten. Das Verschieben der Datei ist eine atomare Aktion, die einen exklusiven Zugriff erfordert und damit eine Racecondition verhindert.
Die Datei wird in das Verzeichnis /tmp/check_mk/hourly/ verschoben und erhält die Endung, *.mk. Wird ein Check nicht stündlich sondern nur täglich vorgenommen, so wird diese Datei in das Verzeichnis /tmp/check_mk/daily/ verschoben. Und so weiter.
Damit die Daten nun übertragen werden ist eine kleine Anpassung des check_mk_agent erforderlich. Wir haben die Ausgabe der Nagios-Plugins in einem Format, welches dem MRPE-Format entspricht, in eine Datei umgelenkt. Diese Dateien werden nun durch den Agent lediglich an der entsprechenden Stelle in den Datenstrom eingefügt.
Im MRPE-Abschnitt wurden hierzu die folgenden Codezeilen ergänzt, die über die Dateien iterieren und die Ausgaben in den Agent-Datenstrom einfügen.
$ diff check_mk_agent /usr/bin/check_mk_agent 56c56 < echo Version: 1.1.8 --- > echo Version: 1.1.8b3 344a345,353 > if [ -d /tmp/check_mk/ ] > then > FILES="/tmp/check_mk/daily/*.mk /tmp/check_mk/hourly/*.mk /tmp/check_mk/weekly/*.mk" > for f in $FILES > do > cat $f > done > fi >
Der wesentliche Unterschied ist nun jedoch, dass die Nagios-Plugins in unserem Falle nicht mehr jede Minute ausgeführt werden, sondern in festen Intervallen per Cron-Job. Der check_mk_agent verwendet jedoch bei jedem Aufruf die Werte aus den zwischengespeicherten Dateien und prüft somit auch weiterhin jede Minute unser System, wobei unsere testergebnisse nicht immer „aktuelle“ Werte enthalten.
Auch eine Inventraisierung ist weiterhin möglich. Sobald die Nagios-Plugins per Cron oder manuell einmalig ausgeführt wurden existieren die temporären Dateien und diese werden vom Agenten ausgeliefert.
Die aufmerksame Leserin wird nun schnell merken, dass es aber einen Haken an diesem Vorgehen gibt. Werden die Nagios-Plugins – warum auch immer – nicht mehr korrekt ausgeführt. Ist das Checkergebnis in den Ergebnisdateien nicht mehr aktuell. Check_MK geht aber weiterhin davon aus, dass alles in Ordnung ist. Um dieses Problem zu lösen löschen wir automatisch alle Ergebnisdateien, die älter sind als das jeweilige Cron-Intervall, in dem die Nagios-Plugins ausgeführt werden.
Daher ist das Skript in /etc/cron.hourly/ entsprechend erweitert:
#!/bin/bash # Loeschen zu alter Dateien TMPWATCH=$(which tmpwatch) $TMPWATCH --mtime 62m /tmp/check_mk/hourly/ $TMPWATCH --mtime 1500m /tmp/check_mk/daily/ $TMPWATCH --mtime 10140m /tmp/check_mk/weekly/ # Ausfuehren der stuendlichen Checks FILES=/etc/check_mk/hourly/* for f in $FILES do $f done
Die Löschung zu alter Dateien wird mit dem Befehl tmpwatch kontrolliert. Hierbei sind die Werte immer ein wenig größer, als das Intervall selbst, damit es nicht zu Überschneidungen kommt.
Der normale Einsatz von MRPE funktioniert weiterhin wie gehabt. Bei unserem Kunden führte diese Umstruktierung der Checkausführung zu einer enormen Beschleunigung der Prüfung. Vor der Umstruktrierung benötigte ein check_mk-Aufruf rund 15 Sekunden nachher waren es lediglich noch 0.3 Sekunden.
# check_mk -nv kvm2 Check_mk version 1.1.8b3 CPU load OK - 15min Load 0.00 at 4 CPUs CPU utilization OK - user: 0.6%, system: 0.5%, wait: 0.0% ... sg9 OK: no SMART errors detected OK - Agent Version 1.1.8b3, processed 41 host infos in 0.3 sec|execution_time=0.279
Für die Einrichtung müssen zunächst die folgenden Verzeichnisse erstellt werden:
- /etc/check_mk/hourly/
- /etc/check_mk/daily/
- /etc/check_mk/weekly/
- /tmp/check_mk/hourly/
- /tmp/check_mk/daily/
- /tmp/check_mk/weekly/
Zusätzlich muss die oben aufgeführte Anpassung am check_mk_agent vorgenommen werden. Und zu guter Letzt müssen für den CronDaemon die Dateien in die entsprechenden Verzeichnisse /etc/cron.hourly/ … eingespielt werden. Das Skript für die stündliche Ausführung ist bereits weiter oben aufgeführt, die beiden anderen Skripte findest du hier:
# cat /etc/cron.daily/check_mk_daily.sh #!/bin/bash # Ausfuehren der taeglichen Checks FILES=/etc/check_mk/daily/* for f in $FILES do $f done
# cat /etc/cron.weekly/check_mk_weekly.sh #!/bin/bash # Ausfuehren der taeglichen Checks FILES=/etc/check_mk/weekly/* for f in $FILES do $f done
[UPDATE]
Ich hab die Anpassungen mal in Skripte zusammengefasst. Auf dem System, welches du überwachen möchtest, muss das folgende Skript einmalig ausgeführt werden.
#!/bin/bash</pre> mkdir -p /etc/check_mk/hourly mkdir -p /etc/check_mk/daily mkdir -p /etc/check_mk/weekly mkdir -p /var/run/check_mk/hourly mkdir -p /var/run/check_mk/weekly mkdir -p /var/run/check_mk/daily if [ -d /usr/lib/check_mk_agent/plugins/ ]; then cat > /usr/lib/check_mk_agent/plugins/mk_mrpe_cron << EOF #!/bin/sh if [ -d /var/run/check_mk/ ] then # Delete old Buffer-Files find /var/run/check_mk/hourly/* -mmin +62 -exec rm -f {} \; find /var/run/check_mk/daily/* -mmin +1500 -exec rm -f {} \; find /var/run/check_mk/weekly/* -mmin +10140 -exec rm -f {} \; echo '<<<mrpe_cron>>>' FILES="/var/run/check_mk/daily/*.mk /var/run/check_mk/hourly/*.mk /var/run/check_mk/weekly/*.mk" for f in \$FILES do cat \$f done fi EOF chmod 755 /usr/lib/check_mk_agent/plugins/mk_mrpe_cron fi #for INTER in 1 2 3 #do # touch /tmp/$INTER #done for INTER in "hourly" "daily" "weekly" do if [ -d /etc/cron.$INTER ]; then cat > /etc/cron.$INTER/check_mk_$INTER << EOF #!/bin/bash INTERVAL=$INTER MV=\$(which mv) TEMPFILENAME=\$(date +%s) if [ -d /etc/check_mk/\$INTERVAL/ ] then grep -hEv '^:space:*(\$|#)' /etc/check_mk/\$INTERVAL/*.cfg | \ while read descr cmdline do PLUGIN=\${cmdline%% *} OUTPUT=\$(eval "\$cmdline") echo "(\${PLUGIN##*/}) \$descr.\$INTERVAL \$? \$OUTPUT" > /tmp/\$TEMPFILENAME.\$descr if [ -d "/var/run/check_mk/\$INTERVAL" ]; then \$MV -f /tmp/\$TEMPFILENAME.\$descr /var/run/check_mk/\$INTERVAL/\$descr.mk else /bin/mkdir -p /var/run/check_mk/\$INTERVAL fi done fi EOF chmod 755 /etc/cron.$INTER/check_mk_$INTER fi done <span style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px;">
Danach kannst du einfach in den neuen Verzeichnissen unterhalb von /etc/check_mk/ jenachdem im Stunden-, Tages- oder Wochenintervall Checks ausführen lassen.
Musst du den folgenden Inhalt in die Datei /usr/share/check_mk/checks/mrpe_cron ablegen. Das Skript basiert auf einer regulären Check_MK-Installation (nicht auf OMD!). Für OMD müssten die Pfadangaben entsprechend angepasst werden.
#!/usr/bin/python # -*- encoding: utf-8; py-indent-offset: 4 -*- # +------------------------------------------------------------------+ # | ____ _ _ __ __ _ __ | # | / ___| |__ ___ ___| | __ | \/ | |/ / | # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / | # | | |___| | | | __/ (__| < | | | | . \ | # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ | # | | # | Copyright Thorsten Robers 2011 <a href="mailto:thorsten@opensource-training.de">thorsten@opensource-training.de</a> | # | based on mrpe from Mathias Kettner | # +------------------------------------------------------------------+ # # This file is part of Check_MK. # The official homepage is at <a href="http://mathias-kettner.de/check_mk">http://mathias-kettner.de/check_mk</a>. # # check_mk is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation in version 2. check_mk is distributed # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more de- # tails. You should have received a copy of the GNU General Public # License along with GNU Make; see the file COPYING. If not, write # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301 USA. def inventory_mrpe_cron(checkname, info): items = [] for line in info: # New Linux agent sends (check_name) in first column. Stay # compatible with MRPE versions not providing this info if line[0].startswith("("): item = line[1] else: item = line[0] items.append((item, None)) return items def check_mrpe_cron(item, params, info): for line in info: if line[0].startswith("("): check_name = line[0][1:-1] line = line[1:] else: check_name = None if line[0] == item: state = int(line[1]) rest = " ".join(line[2:]) parts = rest.split("|", 1) # replace first line break with "<a href="smb://n">\\n</a>" -> Nagios expects it like this output = parts[0].replace("\1", "<a href="smb://n">\\n</a>", 1).replace("\1", "<br>") perfdata = [] if len(parts) > 1: # found pipe symbol perftxt = parts[1].strip() for perfinfo in perftxt.split(" "): try: varname, valuetxt = perfinfo.split("=", 1) values = valuetxt.split(";") perfdata.append(tuple( [varname] + values) ) except: pass # name of check command needed for PNP to choose the correct template if check_name: perfdata.append(check_name) return (state, output, perfdata) return (3, "Check output not found in mrpe_cron checks") check_info['mrpe_cron'] = ( check_mrpe_cron, "%s", 1, inventory_mrpe_cron)
Ich hoffe die Skripte machen es dir ein wenig einfacher. Check_MK auch intervallbezogen zu betreiben. Über Rückmeldungen würde ich mich freuen.