Monitoring von Grails Applikationen mit Zenoss

Um zielgerichtete Performance-Tests durchführen und wirkungsvolle Verbesserungsmaßnahmen ergreifen zu können, muss eine solide Messung der Auslastung aller relevanten Ressourcen (CPU, Hauptspeicher, I/O, …) eingerichtet werden. Dieser Artikel beschreibt das Monitoring von zwei Grails-Applikationen über SNMP mit Zenoss.

Mehrmaschinen-Setup mit Vagrant

Um ein produktionsnahes privates Netzwerk zu simulieren, habe ich drei virtuelle Maschinen mit Vagrant vorbereitet:

Vagrantfile
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.define "zenoss" do |zenoss_server|
    zenoss_server.vm.box = "CentOS-6.2-x86_64"
    zenoss_server.vm.box_url = "https://dl.dropboxusercontent.com/u/17905319/vagrant-boxes/CentOS-6.2-x86_64.box"

    zenoss_server.vm.network :private_network, ip: "10.0.0.2"
    # ...
  end

  (1..2).each do |idx|
    config.vm.define "grails#{idx}" do |grails_web|
      grails_web.vm.box = "squeezy"
      grails_web.vm.box_url = "https://dl.dropboxusercontent.com/u/17905319/vagrant-boxes/squeezy.box"

      grails_web.vm.network :private_network, ip: "10.0.0.#{2 + idx}"
      # ...
    end
  end
end

Installation des Zenoss Servers

Alle Maschinen werden mit Chef provisioniert. Für den Server gibt es eine zugehörige Rolle in roles/zenoss_server.rb. Diese fügt das zenoss::server Recipe zur Run List hinzu, und konfiguriert verschiedene Attribute für Java im Rahmen der Zenoss-Installation.

Vagrantfile
  config.vm.define "zenoss" do |zenoss_server|
    # ...
    zenoss_server.vm.provision :chef_solo do |chef|
      # ...
      chef.add_role "zenoss_server"
      # ...

      chef.json = {
        domain: "localhost"
      }
    end
  end
roles/zenoss_server.rb
name "zenoss_server"
description "Configures the Zenoss monitoring server"

default_attributes(
  "zenoss" => {
    "device" => {
      "properties" => {
        "zCommandUsername" => "zenoss",
        "zKeyPath" => "/home/zenoss/.ssh/id_dsa",
        "zMySqlPassword" => "zenoss",
        "zMySqlUsername" => "zenoss"
      }
    }
  }
)

override_attributes(
  "java" => {
    "install_flavor" => "oracle",
    "jdk_version" => "7",
    "oracle" => {
      "accept_oracle_download_terms" => true
    }
  },
  "zenoss" => {
    "server" => {
      "admin_password" => "zenoss"
    },
    "core4" => {
      "rpm_url" => "http://downloads.sourceforge.net/project/zenoss/zenoss-4.2/zenoss-4.2.4/4.2.4-1897/zenoss_core-4.2.4-1897.el6.x86_64.rpm?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fzenoss%2Ffiles%2Fzenoss-4.2%2Fzenoss-4.2.4%2F4.2.4-1897%2F&ts=1392587207&use_mirror=skylink"
    },
    "device" => {
      "device_class" => "/Server/SSH/Linux"
    }
  }
)

run_list(
  "recipe[zenoss::server]"
)

Installation der Applikationsserver

Um einen Applikationsserver für das Monitoring vorzubereiten, muss der SNMP Daemon installiert werden. Das Simple Network Management Protocol bietet Zugriff auf verschiedene Systemparameter, z.B. CPU-Auslastung, Festplattenzugriffe und Hauptspeicher-Statistiken. Ich habe die gemeinsame Run List und Attribute in roles/monitored.rb zusammengestellt.

Vagrantfile
  (1..2).each do |idx|
    config.vm.define "grails#{idx}" do |grails_web|
      # ...
      grails_web.vm.provision :chef_solo do |chef|
        # ...
        chef.add_role   "monitored"

        chef.json = {
          domain: "localhost",
        }
      end
    end
  end
roles/monitored.rb
name "monitored"
description "Bundles settings for nodes monitored by Zenoss"

default_attributes()

override_attributes(
  "snmp" => {
    "snmpd" => {
      "snmpd_opts" => '-Lsd -Lf /dev/null -u snmp -g snmp -I -smux -p /var/run/snmpd.pid'
    },
    "full_systemview" => true,
    "include_all_disks" => true
  }
)

run_list(
  "recipe[snmp]"
)

Verknüpfen der Applikationsserver mit dem Monitoringdienst

Nun müssen die Applikationsserver dem Zenoss-Server bekannt gemacht werden. Im ersten Schritt habe ich sie manuell über die Web UI eingetragen. Die Web UI ist aus Sicherheitsgründen nur über das Loopback-Interface des Servers erreichbar. Um es aus dem Browser meines Hosts abzurufen, habe ich den HTTP-Verkehr per SSH auf das Loopback-Device getunnelt.

Terminal
ssh -p 2222 -o "UserKnownHostsFile /dev/null" -o "StrictHostKeyChecking no" -N -L 8080:127.0.0.1:8080 root@localhost
# Password is `vagrant'

Nun kann ich auf die UI über localhost:8080 erreichen.

Nach dem Login mit den Zugangsdaten aus roles/zenoss_server.rb kann ich auf das Dashboard zugreifen.

Im Infrastructure Tab kann ich über Add Multiple Devices die Applikationsserver hinzufügen.

Dazu werden die IP-Adressen der beiden virtuellen Applikationsserver, 10.0.0.3 and 10.0.0.4, eingetragen, und der Standardwert als device type (Linux Server SNMP) beibehalten.

Zenoss fügr diese beiden Maschinen im Hintergrund zu seinem Server-Pool hinzu.

Danach beginnt Zenoss damit, Events und Messwerte aufzuzeichnen. Dies ist ein Beispiel aus einer einfachen Lastsimulation der Grails-Applikation auf grails2, 10.0.0.4.

Mit diesen Vorbereitungen können wir neue Abenteuer im Dickicht der Serverperformance in Angriff nehmen.

Der Quellcode aus diesem Artikel ist auf GitHub verfügbar.