This entry is part 1 of 5 in the series Icinga 2 Best Practice

Heute bin ich endlich mal wieder dran einen Blogpost zu schreiben und wie jedes Mal, kann ich mich nicht entscheiden über welches Thema ich berichten möchte. Eigentlich sollte hier nach meinem Plan ein Post über den Rewrite des Icinga 2 Moduls für Puppet stehen. Aber wie schon häufiger habe ich mich in nahezu letzter Sekunde umentschieden und möchte heute mit einer Reihe starten, in der es um die Organisation von Icinga 2 Host- und Service-Objekten gehen wird. Den Start macht der erste Teil zur Konfiguration des Icinga 2 Agenten.
Im Icinga-Kosmos gibt es im Grunde zwei unterschiedliche Arten von Plugins. Bei der Ersten handelt es sich um Plugins, die ihre Werte über eine Netzwerkverbindung ermitteln z.B. check_http. Die zweite Art sind dann solche, die ihre Werte lokal auf dem zu überwachenden Host ermitteln müssen wie check_disk oder check_load. Mit dem Agenten ist uns seit geraumer Zeit eine Möglichkeit in die Hand gegeben mit der diese letzteren Plugins lokal ausgeführt werden können. Hierbei wird vom eigentlichen Icinga 2 Server eine persistente, verschlüsselte und an Hand von Zertifikaten authentifizierte Verbindung zum zu überwachenden Host aufgebaut. Über diese stößt dann der Server auf dem Agenten die Ausführung des gewünschten Plugins an.
Die eigentlich Installation, z.B. mit dem node wizard ist hier bitte der Online-Dokumentation zu entnehmen. Bzgl. der Konfiguration ist am Agenten zu hinterlegen wer hier überhaupt mit einander kommuniziert.

# cat /etc/icinga2/zones.conf
object Endpoint "agent.example.org" {
}
object Endpoint "server.example.org" {
  host = "x.x.x.x"
}
object Zone "agent.example.org" {
  endpoints = ["agent.example.org"]
  parent = "master"
}
object Zone "master" {
  endpoints = ["server.example.org"]
}

Jedes Endpoint-Objekt ist eine laufende Icinga-Instanz. Einer Zone muss immer mindestens ein Endpoint zugeordnet sein. Daten werden zwischen Zonen ausgetauscht. Hier sorgt das parent-Attribut, dass Checkresults an die Master-Zone und damit an deren Endpoints geliefert werden. Für das Objekt server.example.org vom Type Endpoint ist das Attribut host mit der zugehörigen IP-Adresse gesetzt, damit ist konfiguriert, dass der Agent die Verbindung zum Server aufbaut.
Auch der andere Kommunikationspartner in der master-Zone muss wissen von wem er Daten empfangen und an wen er selbst welche senden darf. Dort schreiben wir jedoch lediglich die Information zur eigenen Seite in die Datei zones.conf.

# cat /etc/icinga2/zones.conf
object Endpoint "server.example.org" {
}
object Zone "master" {
  endpoints = ["server.example.org"]
}

Das agentenzugehörige Endpoint- und Zonen-Objekt kommt mit dem Host-Objekt zusammen in eine “normale” Konfigurationsdatei für zu überwachende Objekte, z.B. unterhalb von /etc/icinga2/conf.d.

object Endpoint "agent.example.org" {
}
object Zone "agent.example.org" {
  endpoints = ["agent.example.org"]
  parent = "master"
}
object Host "agent.example.org" {
  import "generic-host"
  display_name = "agent"
  ...
}

Dies erleichtert einem in zweierlei Hinsicht die Konfiguration:

1) Es stehen alle Informationen an einer Stelle und können beim Wegfall des Hosts auch dort zusammen entfernt werden ohne noch zusätzlich an anderen Orten suchen zu müssen.
2) Betreibt man Satelliten, wird so das Endpoint- und Zonen-Objekt via Synchronisation der Konfiguration automatisch auf den entsprechenden Satelliten verteilt bzw. entfernt.

Auf dieser Seite verzichte ich auf die Angabe einer IP mittels host, d.h. es erfolgt kein Versuch eines Verbindungsaufbaus zum Agenten. Der Server warte also darauf das der Agent von sich aus die Kommunikation initiiert. Zu überwachende Hosts werden auch mal gewartet und sind dann nicht erreichbar. So erfolgen keine überflüssigen Verbindungsversuche und schreiben das Logfile voll. Ein weiterer Tipp ist, die Namen für Endpoint- und Host-Objekt identisch zu wählen. Damit sieht eine Servicedefinition z.B. für load wie folgt aus:

apply Service "load" {
  import "generic-service"
  check_command = "load"
  command_endpoint = host.name
  assign where host.vars.os == "Linux"
}   

Da check_load auf einem Endpoint (Agenten) auszuführen ist, wird mit dem Service-Attribut command_endpoint festgelegt auf welchem dies zu erfolgen hat. Ein Service ist immer einem Host zugeordnet, so kann aus dem Service heraus auf Attribute des zugehörigen Hosts zugegriffen werden. Da für command_endpoint ein existierender Endpoint anzugeben ist, wir diesem per Konvention den selben Namen wie dem Host-Objekt gaben, kann hier nun host.name benutzt werden.

TIPP: Kommen keine Ergebnisse vom Agenten auf dem Icinga-Server (Master) an, fehlt auf Seite des Agenten die Angabe der parent-Zone. Wird keine Konfiguration zum Agenten synchronisiert, fehlt die parent-Zone auf der Seite des Servers.

Zum Thema synchronisieren von Konfigurationsdateien und globalen Zonen, dann in Teil 2.

Lennart Betz

Autor: Lennart Betz

Der diplomierte Mathematiker arbeitet bei NETWAYS im Bereich Consulting und bereichert seine Kunden mit seinem Wissen zu Icinga, Nagios und anderen Open Source Administrationstools. Im Büro erleuchtet Lennart seine Kollegen mit fundierten geschichtlichen Vorträgen die seinesgleichen suchen.