Ich bin nun seit einigen Wochen stolzer Besitz eines QNAP TS-332X. Und meinem Beruf geschuldet, suche ich natürlich nach kurzer Zeit Möglichkeiten aus dem NAS das Maximum raus zu holen. QNAP bietet hier mit Container Station (LXC & Docker-Container) eine sehr vielversprechende Lösung um eigene Anwendungen auf dem NAS zu betreiben. Möglichkeiten das System zu monitoren gibt es hier bereits auch mit Boardmitteln, allerdings nur mit Mail oder SNMP.

Letzteres ist so schon ganz nett, jedoch für mich nicht wirklich alleinstehend brauchbar. Also musste eine bessere Lösung her, am Besten eine Anbindung an die bestehende Infrastruktur mit dem Prometheus-Stack, den ich bereits auf meinem vServer betreibe.

Voraussetzungen für diesen Post

Um mit diesem Post was anfangen zu können, solltest du zumindest grob Bescheid wissen, über ...

  • Prometheus
  • Docker (+ lokale Installation)

Ist das bei dir der Fall - go on, ansonsten ist das wohl eher non-sense für dich ;) Alternativ kannst du dir beides etwas aneignen und dann wieder kommen.

SNMP?!

SNMP wird auf Wikipedia relativ ausführlich beschrieben. Einfach gesagt ist es ein steinaltes Netzwerkprotokoll um Daten von Geräten abzufragen, die via Netzwerk erreichbar sind. Glorreicherweise wird hier UDP verwendet, das lasse ich jetzt einfach mal so stehen.

Um Daten abzufragen setzt man auf OIDs, die sind jeweils Schlüssel zu einem Wert, der einen spezifizierten Typ haben kann. Nachdem Nummern nicht gerade leicht zu merken sind, gibt es hierfür MIB-Files. Diese enthalten wie eine Art Inhaltsverzeichnis mit menschenlesbarem Namen, Datentyp und im Ideallfall auch noch eine mehr oder weniger nützliche Dokumentation.

Je nach Gerät und Hersteller funktioniert das auch mehr oder weniger zuverlässig. Ich durfte persönlich schon öfter feststellen, dass Einträge im MIB standen, die das Gerät gar nicht konnte oder nur einen Dummy-Wert zurücklieferten. QNAP liefert hier allerdings einen ziemlich stabilen Stand. Also deine Haare sollten danach, zumindest nicht wegen einer fehlerhaften MIB ausfallen.

Aktivieren in QTS (Management UI fürs NAS)

Damit wir SNMP verwenden können, müssen wir dem Gerät erst mal mitteilen, dass er einen Port aufmachen soll, um dort unsere Anfragen zu beantworten.

Dazu erstmal am NAS anmelden, anschließend ins Control Panel wechseln ...

Home-Screen von QTS

Danach wechselst du unter Network & File-Services zu SNMP ...

Geöffnetes Control Panel

Hier setzt du die Checkbox  Enable SNMP service, ich verwende bei mir die SNMP-Version 2, diese bietet keine echte Authentifizierung an, ist aber auch nur in meinem Heimnetzwerk verfügbar, das Risiko gehe ich also an dieser Stelle ein ...

SNMP Einstellungen

Die SNMP-Version setzt du auf SNMP V1/V2 und bei Community trägst du einfach public ein.

Die MIB kannst du hier auch gleich herunterladen, wir benötigen sie später noch.

Wie kommt das SNMP-Zeugs in Prometheus?

Zum Glück gibt es für Prometheus für so ziemlich alles Exporter, und wenn es keinen gibt kann man sich einen schreiben. Glücklicherweise gibt es hier von Prometheus schon den snmp-exporter, dieser macht uns an der Stelle das Leben schon mal leichter.

Die Konfiguration ist manuell sehr nervig zu schreiben, also bekommt man einen Generator oben drauf mit geliefert. Dieser findet sich im GitHub-Repo unter generator/, kann aber auch mit einem fertigen Docker-Image ausgeführt werden. Das mit Docker wird allerdings nicht allzu groß erwähnt (wieso auch immer).

Konfiguration generieren

Ich bevorzuge die Konfiguration via Docker zu erstellen, das geht schnell und unkompliziert, dazu legst du erstmal irgendwo einen Ordner an, den wir verwenden werden um die Konfiguration zu erzeugen.

Jetzt legst du einen Unterordner an mit dem Namen mibs, in diesen kopierst du zuerst die heruntergeladenen MIB deines NAS. Anschließend öffnest du die File mit einem Text Editor deiner Wahl, relevant ist für uns nur der obere Teil in der Datei:

NAS-MIB DEFINITIONS ::= BEGIN

   IMPORTS
      enterprises, Counter, TimeTicks
         FROM RFC1155-SMI
      Integer32, Counter32, IpAddress, Unsigned32, Counter64, OBJECT-TYPE
         FROM SNMPv2-SMI
      TRAP-TYPE
         FROM RFC-1215;

      -- From RFC-1213 (MIB-II)
      DisplayString ::= OCTET STRING

Je nach Modell können die Imports hier abweichen, wichtig ist, dass alle MIBs die hier importiert werden, auch im mibs Ordner landen. Eine simple Google-Suche hilft in dem Fall, meine MIBs habe ich alle von http://www.circitor.fr/ heruntergeladen (z. B. http://www.circitor.fr/Mibs/Html/R/RFC1155-SMI.php).

Ermitteln der relevanten Metriken

Ist das erledigt, müssen wir erst einmal herausfinden welche Metriken wir denn eigentlich sammeln bzw. auswerten wollen. Hierfür gibt es diverse SNMP-Browser, ich persönlich nutze hier gerne den MIB-Browser von ireasoning, dieser funktioniert auf Windows & Linux gleichermaßen.

Die MIB für dein NAS kannst du entsprechend durch einen Rechtsklich auf MIB Tree laden lassen. Bei Adresse trägst du die lokale IP-Adresse deine NAS ein ...

MIB-Browser

Im Baum kannst du anschließend durch Doppelklick Metriken laden, bzw. durch anklicken die Doku anzeigen ...

Ergebnis einer Abfrage

Generieren der Exporter-Konfiguration

Der Exporter speist sich von der generator.yml, diese enthält alle OIDs bzw. deren Namen, die für dich relevant sind. Meine sieht z. B. so aus:

modules:
  qnap_nas:
    walk:
      - raidStatus
      - systemFanSpeed
      - systemTemperatureEX
      - cpuUsage
      - diskSmartInfo #  INTEGER {abnormal(2),warning(1),good(0),error(-1)}
      - diskTemperture
      - enclosureSystemTemp
      - sysVolumeFreeSize
      - sysVolumeTotalSize
      - systemTotalMem
      - systemFreeMem
      - ifPacketsSentEX
      - ifPacketsReceivedEX
      - ifErrorPacketsEX
    version: 2
    max_repetitions: 25
    retries: 3
    timeout: 3s
    lookups:
      - source_indexes: [ifIndexEX]
        lookup: ifDescrEX
        drop_source_indexes: true
      - source_indexes: [hdIndex]
        lookup: hdDescr
        drop_source_indexes: true
      - source_indexes: [diskIndex]
        lookup: hdDescr
        drop_source_indexes: true
      - source_indexes: [hdIndexEx]
        lookup: hdDescrEx
        drop_source_indexes: true
      - source_indexes: [sysVolumeIndex]
        lookup: volumeName
        drop_source_indexes: true
      - source_indexes: [enclosureIndex]
        lookup: enclosureName
        drop_source_indexes: true
    overrides:
      raidStatus:
        regex_extracts:
          "":
            - regex: '.*Ready'
              value: 1
            - regex: '.*'
              value: 0
      systemTotalMem:
        regex_extracts:
          _mb:
            - regex: '(.*) MB'
              value: '$1'
      systemFreeMem:
        regex_extracts:
          _mb:
            - regex: '(.*) MB'
              value: '$1'
      sysVolumeFreeSize:
        regex_extracts:
          _gb:
            - regex: '(.*) GB'
              value: '$1'
      sysVolumeTotalSize:
        regex_extracts:
          _gb:
            - regex: '(.*) GB'
              value: '$1'

Bei Walk gibt man alle OIDs bzw. deren Bezeichnungen an, die relevant sind. Um das ganze Format noch etwas aufzubrechen bzw. umzuwandeln gibt es den Block mit den overrides und regex. Mehr dazu im Anschluss.

Lookups

Mit Lookups kannst du z. B. den relativ nichtssagenden Namen einer volumeId, die fortlaufend ist zu dem Namen ändern, den du über die QTS-Oberfläche vergeben hast. Solche Replacements brauchst du meistens wenn die gleiche Metrik für mehrere Dinge vorkommen kann, eben z. B. Volumes:

Aufbau in der MIB

Die Zuordnung läuft hierbei z. B. so:

SNMP-Daten:
volumeFreeSize.1 => 100 GB
volumeName.1 => documents

Metrik mit lookup:
volumeFreeSize{volumeName="documents"} 100 GB

Metrik ohne lookup:
volumeFreeSize{volumeIndex="1"} 100 GB

Die Metrik ist als Text mit Einheit in einem so natürlich nicht gültig. Der Exporter generiert sie hier mit als Label und gibt als Wert immer 1 zurück, aus Gründen der Lesbarkeit und Veranschaulichung hab ich das an dieser Stelle eiskalt ignoriert.

regex_extracts

Natürlich ist das GB in der Metrik oben nicht hilfreich, schliesslich wollen wir ja z. B. mit dieser Zahl rechnen. Das es sich hier um Gigabyte(s) handelt, müssen wir auch nicht bei jedem Wert nocheinmal serviert bekommen. Um den Part mit der Einheit wegzuschneiden kommt ein regex_extract zum Einsatz, wie auch oben verwendet. Im YAML sieht das dann so aus:

sysVolumeTotalSize:
  regex_extracts:
     _mb:
       - regex: '(.*) GB'
         value: '$1'

So wird aus der Metrik sysVolumeTotalSize -> sysVolumeTotalSize_mb, welche nur die Zahl ohne Einheit enthält.

Wenn die Konfiguration soweit abgerundet wurde, ist es an der Zeit die Konfiguration zu generieren, unter Linux sieht das so aus:

docker run --rm -it -v "${PWD}:/opt" prom/snmp-generator generate
PWD steht hier für das aktuelle Verzeichnis

Der Generator baut auf Basis der Informationen aus den MIBs und einer generator.yml eine snmp.yml, die du so an deinen Exporter füttern kannst ...

Beispielausgabe

Exporter betreiben

Der Exporter kann auf einem anderen Gerät wie z. B. einem Rasperry Pi etc. betrieben werden, ich habe mich allerdings entschieden den Exporter via Docker auf dem NAS selbst zu betreiben. An dieser Stelle aber eine kleine Warnung: Wenn du das Logging für den Container nicht deaktivierst kann dein NAS nicht in den Disk Spindown gehen.

Zum Testen habe ich das mal so gelassen, nach gut einer Woche stabilem Betrieb habe ich dann allerdings den Logging-Driver auf none gestellt, dadurch wird kein Log geschrieben. Wenn nicht grade die Container-Station oder andere Komponenten des QNAP NAS sich entschliessen auf der Platte wild Dateien zu schreiben oder zu lesen funktioniert das soweit auch ganz gut. Unterm Strich geht das NAS aber deutlich seltener in den Spin-Down.

Anpassungen am Image

Nachdem Prometheus auf meinem Server läuft, muss der Exporter entsprechend über das Internet erreichbar sein. Um nicht Spammern & Script-Kiddies Tür und Tor zu öffnen, habe ich den Exporter nochmal in eine Mini-Go-App verpackt. Grund hierfür ist die Erweiterung um einen billigen Authentifizierungsmechanismus via festgefrästem Token. Das ist ziemlich pragmatisch aber hoch effektiv und semi-sicher.

Das entsprechende Image, bzw. Gebastel findest du in diesem Github-Repo meines Accounts.

Ab hier kannst du den Exporter noch entsprechend in der Firewall freigeben und wie gewohnt bei Prometheus als Scrape Target einstellen.

Fazit

Das Monitoring meines QNAP NAS mit Prometheus ist am Anfang etwas holprig gewesen, vorallem aufgrund der fehlenden Dokumentation über die Feinheiten des snmp_exporter. Dank (oder leider wegen) meiner Erfahrungen mit SNMP war es dann aber relativ einfach die Puzzle-Teile vernünftig an mein bestehendes Monitoring anzubauen.

Alerts für das NAS lassen sich mit Prometheus relativ einfach realisieren und geben mir so schnell aktive Hinweise wenn etwas auf ein Limit zusteuert oder einen kritischen Watermark. Das funktioniert so auch schon mit zahlreichen Diensten und dem Health-Status des Host-OS und bereichert jetzt auch noch mein NAS.

Das fertige Dashboard für mein QNAP NAS findest du auf grafana.com. Das Ganze ist natürlich an meine persönlichen Anforderungen und das Modell zugeschnitten. Konzeptionell bietet es doch schon mal einen kleinen Vorgeschmack und evtl. sogar wiederverwendbare Teile.