Cloud Management – Teil 1: blkdeviotune/migrate-setmaxdowntime


Viele von euch haben bestimmt schon einmal von OpenNebula oder OpenStack gehört, beiden Plattformen verwenden standardmäßig libvirtd als Hypervisor, da jedoch die darunter liegende Hardware mit unter stark beansprucht werden wird, vor allem im Cloud Bereich, wo mehrerer KVM Instanzen auf einem Virt Host um CPU/Speicher/IO Resourcen konkurrieren, ist es gelegentlich notwendig die einen oder andere Instanz zu bändigen bzw. in die Schranken zu weisen.
Unsere Cloud läuft derzeit noch mit OpenNebula, wir selbst sind sehr zufrieden mit dem Stack, da sich dieser leicht Verwalten lässt und sich auch gut mit unserem Ceph als Backend verträgt, natürlich verwenden wir in unserem Cloud Stack noch andere Tools, diese sind aber nicht Gegenstand dieses Artikels, mehr dazu in späteren Teilen der Serie.
Libvirtd kann mit CLI Tools wie virsh gesteuert werden, auch besteht die Möglichkeit libvirtd über die entsprechende libvirt C API oder durch seine ScriptLanguage Bindings für ruby/python/perl/javascript/etc… anzusprechen bzw. anzusteuern zu können.
So beispielsweise unterstützt man OpenNebula wenn die Migration einer KVM Instanz von Virt Host A zu Virt Host B aufgrund von Last auf der Instanz selbst partout nicht klappen will…

root@virt1: ~ $ virsh migrate-setmaxdowntime --downtime 1800 one-8366
error: Requested operation is not valid: domain is not being migrated (dieser Fehler kommt nur wenn sich die Instanz nich im Status Migrate befindet, ist hier also nur exemplarisch mit abgebildet)

…oder wenn die Instanz AMOK läuft und somit andere Instanzen zu stark beeinträchtigt…

root@virt1: ~ $ virsh blkdeviotune one-8366 vda --live
total_bytes_sec: 62914560
read_bytes_sec : 0
write_bytes_sec: 0
total_iops_sec : 400
read_iops_sec  : 0
write_iops_sec : 0

…dann limitieren wir diese einfach ein bisschen…

root@virt1: ~ $ virsh blkdeviotune one-8366 vda --live 62914560 0 0 200 0 0

…und vergewissern uns nochmal ob unsere neuen IOPs Limits übernommen wurden…

root@virt1: ~ $ virsh blkdeviotune one-8366 vda --live
total_bytes_sec: 62914560
read_bytes_sec : 0
write_bytes_sec: 0
total_iops_sec : 200
read_iops_sec  : 0
write_iops_sec : 0

…ich denke, damit sollte klar sein worauf wir hier abzielen möchten.
In folgenden Teilen dieser Serie werden wir euch noch mehr Tips & Tricks mit auf den Weg geben, die helfen sollen eure Cloud zu bändigen bzw. aufkommende Probleme anzugehen, also bleibt gespannt. 😉

NodeJS HA mit PM2…

ich hatte in Vergangenheit bereits einen Blog Post über NodeJS in Verbindung mit dem NodeJS ‘Cluster’ Modul geschrieben ( siehe hier ), nun möchte ich euch zeigen wie Ihr eure NodeJS Anwendung auch ohne Programmierarbeit (also als reine Ops Tätigkeit) zum Cluster umfunktioniert und wie ihr diese anschließend verwalten könnt.
nodejs-logo-2015
Legen wir los, wir benötigen hierzu NodeJS, am besten 4.4 LTS und 4 zusätzliche Module/Helper, fangen wir also mit der Installation an…

$ npm install -g pm2
$ npm install -g express-generator
$ mkdir ~/project && cd project
$ npm install --save express
$ npm install --save sleep

…nun generieren wir das Express Anwendungsgerüst…

$ express -f .
   create : .
   create : ./package.json
   create : ./app.js
   create : ./public
   create : ./public/javascripts
   create : ./public/images
   create : ./public/stylesheets
   create : ./public/stylesheets/style.css
   create : ./routes
   create : ./routes/index.js
   create : ./routes/users.js
   create : ./views
   create : ./views/index.jade
   create : ./views/layout.jade
   create : ./views/error.jade
   create : ./bin
   create : ./bin/www
   install dependencies:
     $ cd . && npm install
   run the app:
     $ DEBUG=project:* npm start
$

… danach löschen wir in der Datei app.js alles von Zeile 13 bis 58, wir benötigen nur das Gerüst selbst und ein paar Zeile selbst geschriebenen Code, um diesen kommen wir leider nicht herum, da wir ja auch was sehen wollen.
Fügt nun ab Zeile 14 folgenden Code hinzu…

var crypto = require( 'crypto' );
var util = require( 'util' );
var sleep = require( 'sleep' ).sleep;
function getRandHash() {
    var current_date = (new Date()).valueOf().toString();
    var random = Math.random().toString();
    return crypto.createHash('sha1').update(current_date + random).digest('hex');
}
var myID = getRandHash();
app.get( '/', function( req, res ) {
    sleep( Math.floor( (Math.random() * 3) + 1 ) );
    res.send({
        "ID": myID,
        "PID": process.pid,
        "ENV": process.env
    });
});

…nun starten wir die App über PM2 im Cluster Mode, hier bitte dem Parameter ‘-i’ nur einen Wert gleich der Anzahl der CPU Cores mitgeben. Dann testen wir das Ganze doch gleich mal…

$ cd project
$ pm2 start bin/www -i 4

…ihr solltet nun folgende Ausgabe zu sehen bekommen…
pm2-start-www-cluster
…ihr könnt eure Anwendung auch auf Fehler überprüfen, dafür gibt euch PM2 einen Parameter ‘logs’ mit, der wiederum einige Flags kennt. Wenn ihr nur ‘pm2 logs’ eingebt dann bekommt ihr die Standardausgabe unserer Anwendung zu sehen, wenn ihr zusätzlich das Flag ‘–err’ mit angebt, bekommt ihr die Standard Fehlerausgabe, was für das Debugging recht hilfreich ist.
pm2-logs-examine
So, nun könnt ihr in eurem Browser mal die Anwendung aufrufen. Der Listener der Anwendung horcht auf dem Port 3000. Ein Aufruf auf http://127.0.0.1:3000 sollte ein JSON liefern, ähnlich zu dieser Ausgabe hier…
pm2-cluster-test1
Da wir in unserem Code eine künstliche Verzögerung eingebaut haben, könnt ihr nun mit 2 direkt Aufeinander folgenden Browser Reload sehen das sich die ID u. PID Werte gelegentlich ändern, dies bedeutet, dass unsere Cluster Anwendung funktioniert.
pm2-logo
Ich hoffe ich konnte euch nun zum Spielen und Experimentieren animieren. PM2 wird von der Firma Kissmetrics als OpenSource Project stetig weiter entwickelt und hat noch so viel mehr zu bieten, ganz findige unter euch werden die Monitoring API zu schätzen wissen und diese vmtl. in Icinga2, Graphite, Kibana und anderen Lösungen integrieren wollen.
Dann bis demnächst 🙂

GitLab – Webhooks

gitlab-webhooks
Da ich vor kurzem für einen unserer namhaften Kunden ein GitLab Setup aufsetzten durfte und dieser sich nun auch Automatische Checkouts seiner Live Branches auf seinen Produktiv Systemen wünschte, habe ich mich dazu entschlossen euch ein bisschen an der Einrichtung dieser Mechaniken teilhaben zu lassen, natürlich nicht im vollem Umfang des Projektes für unseren Kunden, das eine oder andere habe ich für diesen Artikel verständlicherweise leicht abwandeln müssen, das hier gezeigte funktioniert trotzdem, ich habe es selber ausprobiert.
Dann legen wir mal los…
In einem klassischen Git Setup werden die Hooks direkt im Repository im Unterordner hooks abgelegt, hier mal ein Beispiel wie das aussehen kann…

$ MyAwesomeProject/hooks $ ll
-rwxrwxr-x 1 enzo enzo  452 Jun 28 11:46 applypatch-msg.sample*
-rwxrwxr-x 1 enzo enzo  896 Jun 28 11:46 commit-msg.sample*
-rwxrwxr-x 1 enzo enzo  189 Jun 28 11:46 post-update.sample*
-rwxrwxr-x 1 enzo enzo  398 Jun 28 11:46 pre-applypatch.sample*
-rwxrwxr-x 1 enzo enzo 1642 Jun 28 11:46 pre-commit.sample*
-rwxrwxr-x 1 enzo enzo 1239 Jun 28 11:46 prepare-commit-msg.sample*
-rwxrwxr-x 1 enzo enzo 1352 Jun 28 11:46 pre-push.sample*
-rwxrwxr-x 1 enzo enzo 4898 Jun 28 11:46 pre-rebase.sample*
-rwxrwxr-x 1 enzo enzo 3611 Jun 28 11:46 update.sample*

GitLab geht hier allerdings einen anderen Weg, da dieses das hooks Verzeichnis durch einen Symbolischen Link auf System eigene Hooks umlenkt (wie hier Beispielhaft zu sehen ist)…
gitlab-webhooks-art2
…nun sollte man hier auch besser die Finger heraus lassen, da GitLab dieses Verzeichnis für allerlei anderen Mechaniken benötigt, der Weg über die Webhooks ist meiner Meinung nach aber auch flexibler (allein schon wegen der einfachen Anbindung an Web Dienste wie GitHub, Bitbucket, Heroku, etc.).
Nun direkt zum spaßigen Teil, im GitLab benötigen wir einen neuen User ohne irgendwelche besonderen Rechte incl. SSH Public Key, fangen wir mit dem Key selbst an, da der Checkout User keinen besonderen Rechte benötigt außer einen Pull/Fetch zu tätigen, reicht es uns den Key also entsprechend Unprivilegiert zu preparieren (bei der Passwortabfrage bitte nichts angeben, einfach mit Enter bestätigen)…

$ ssh-keygen -t rsa -b 2048 -O clear -O no-agent-forwarding -O no-port-forwarding -O no-pty -O no-user-rc -O no-x11-forwarding -f gitlab.key
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in gitlab.key.
Your public key has been saved in gitlab.key.pub.
The key fingerprint is:
4b:f3:ae:60:d4:5d:5e:02:75:64:4c:7f:ce:09:ec:8a enzo@ebony
The key's randomart image is:
+--[ RSA 2048]----+
|          ...+=  |
|           ..o.. |
|            oo. o|
|       . . o.o.oo|
|      . S . .. .o|
|     . . +. .    |
|      o .E..     |
|     . . .       |
|        ...      |
+-----------------+
$ ll
insgesamt 8
-rw------- 1 enzo enzo 1675 Jun 28 11:52 gitlab.key
-rw-r--r-- 1 enzo enzo  392 Jun 28 11:52 gitlab.key.pub

…nun benötigen wir lediglich noch einen User im GitLab, das sollte keine große Herausforderung darstellen, bitte stellt auch sicher das ihr den SSH PublicKey in unserem Beispiel gitlab.key.pub dem User, lasst ihn uns hier der Einfachheit halber checkout nennen zuweist, da die Webhooks mit den Berechtigungen des Standard Apache User www-data läuft (das ist zumindest unter Debian/Ubuntu der Fall, unter Redhat Systemen heißt dieser wwwrun) solltet ihr dem Key als Identifier so etwas wie www-data to gitlab oder ähnliches benennen, damit ihr später ganz einfach den Überblick behalten könnt…
gitlab-webhooks-art4
gitlab-webhooks-art5
…nun müssen wir unserem User checkout lediglich noch in unser Projekt aufnehmen, die Rechte eines Reporter sollten dafür ausreichend sein um Fetch/Pull oder auch Clone zu können, mehr benötigen wir an dieser Stelle nicht…
gitlab-webhooks-art9
…somit sind wir auf schon fast fertig, zumindest was das GitLab Setup selbst betrifft, nun müssen wir lediglich noch die URL unseres Webhook konfigurieren und schon können wir uns dem Hook selber widmen…
gitlab-webhooks-art7
gitlab-webhooks-art8…bitte beachtet auch, das es beim Entwickeln eines Webhooks sehr hilfreich sein kann wenn ihr über den Button [Test Hook] den Push Event einfach mal Manuell triggert, ansonsten würde euer Webhook erst aufgerufen werden wenn ihr wirklich in das Repository Pusht (das geht natürlich auch, legt euch hierzu einfach ein neues Repository zum spielen an).
So nun geht es an den Server der unseren Webhook ausführen soll, ihr benötigt lediglich einen simplen Apache/NginX vHost mit Standard Rechten, man kann selbstverständlich auch ein komplizierteres Deployment bauen aber darum geht es in diesem Artikel nicht (ich nutzte hier den Apache2 mit PHP5, da dieser bereits auf dem Kunden System vorhanden wahr und zusätzliche Scriptsprachen installieren ist meist schlechte Praxis sowie auch unnötiger Aufwand).
Ich habe mich hier für den Standard Pfad des Apache Setups entschieden da der Standard vHost bereits auf diesen zeigt und dieser auch nur aus dem internen Netz bedienbar ist, somit ist sichergestellt das Niemand von außerhalb Unfug treiben kann.
Dort habe ich im DocumentRoot des Apache ein Verzeichnis api erstellt, der volle Pfad lautet hier /var/www/html/api, dort habe ich mein Webhook mit Namen on-push.php abgelegt, dieser hat nun folgenden Inhalt…

object_kind == 'push' ) {
                if( $obj->ref == 'refs/heads/'.BRANCH ) {
                    $allowed = false;
                    foreach( $USERS as $user ) {
                        msg( "permission test ( ".$obj->user_name ." == ". $user." ) ..." );
                        if( preg_match( "/$user/i", $obj->user_name ) ) {
                            msg( $user . " allowed to do updates on refs/heads/".BRANCH." branch" );
                            $allowed = true;
                            break;
                        }
                    }
                    if( $allowed ) {
                        if( $obj->before != "0000000000000000000000000000000000000000" ) {
                            msg( "changing directory to ".PROJECTROOT );
                            chdir( PROJECTROOT );
                            msg( "executing: ". COMMAND );
                            $fh = popen( COMMAND." 2>&1", "r" );
                            $result = fread( $fh );
                            while( !feof( $fh ) ) {
                                msg( rtrim(fgets( $fh, 4096 )) );
                            }
                            pclose( $fh );
                        } else {
                            msg( "it's a empty repository, we'll do nothing at this point" );
                        }
                    } else {
                        msg( "permission denied for ". $obj->user_name );
                    }
                } else {
                    msg( "everybody can push to ". $obj->ref.", but we'll do nothing, please check your project settings" );
                }
            } else {
                msg( "[ ". $obj->object_kind ." ] event handler not yet implemented" );
            }
        } else {
            msg( strtoupper($_SERVER['REQUEST_METHOD'])." from [ ".$_SERVER['REMOTE_ADDR'] ." ] is not allowed, please check your server settings" );
            return_status( ERR );
        }
    } catch( Exception $e ) {
        msg( "======= EXCEPTION BEGIN ========" );
        msg( $e->getMessage() );
        msg( "======= EXCEPTION END ==========" );
        return_status( ERR );
    }
    return_status( OK );
    // ================================ FUNCTIONS ===========================================
    function return_status( $status = ERR ) { header( $status ); }
    function getRequestBody() { return json_decode( file_get_contents('php://input') ); }
    function msg( $message ) { if( $message != null ) file_put_contents( LOGFILE, $message."\n", FILE_APPEND ); }
?>


..damit das nun funktionieren kann, müssen wir nun noch das Projekt Klonen und die SSH Settings anlegen, fangen wir daher direkt mit den SSH Settings an…

# (beginne mit Root Login)
su - -s /bin/bash www-data
mkdir -p .ssh && chmod 0600 .ssh
exit
cp gitlab.key /var/www/.ssh/ && chown www-data. /var/www/.ssh/gitlab.key && chmod 0400 /var/www/.ssh/gitlab.key
su - -s /bin/bash www-data
vi .ssh/config

…die .ssh/config sieht dabei wie folgt aus…

Host gitlab.example.org
    UserKnownHostsFile /dev/null
    StrictHostKeyChecking no
    IdentityFile ~/.ssh/gitlab.key
    User git
    LogLevel VERBOSE

…speichert nun das ganze und Klont eurer Projekt nach /var/www/project1/htdocs

# (beginne mit Root Login)
su - -s /bin/bash www-data
cd /var/www/project1
git clone git@gitlab.example.org:test/number1.git htdocs

…wenn ihr nun Lokal mit eurer Arbeitskopie arbeitet und an dem Punkt seit das ihr alles fertig zuhaben scheint und dann einen Push in euren staging Branch macht, wird GitLab jedesmal den Webhook on-push.php Aufrufen und auf dem Projekt/Web -Server einen Fetch/Pull ausführen lassen, um das Projekt auf den selben Stand wie eure Arbeitskopie zu bringen.
Zugegeben der PHP Handler oben ist keinesfalls perfekt, ich bin auch kein guter PHP Programmierer, genau genommen eigentlich gar keiner ;). Der Hook für das Kunden Projekt umfasst zudem noch mehr Fähigkeiten und würde mit seine zu diesem Zeitpunt ca. 800 Zeilen diesen Artikel in jedem Fall sprengen, aber ich denke das der gezeigte Webhook oben bereits eine gute Ausgangsbasis darstellt, sodass ich euch hoffentlich dazu Animieren konnte, das ganze doch einmal selber nachzubauen.
Zum zweck des Debugging, loggt dieser zur Kontrolle nach /var/www/html/api/on-push.log , hier lohnt also ein Blick.
Noch ein kleiner Hinweis meinerseits, der eine oder andere von euch wird schnell feststellen, das GitLab selber im Admin Panel auch einen Menü Eintrag mit der Bezeichnung [Deploy Keys] bereitstellt, womit sich das oben gezeigte auch umsetzten lässt, aufgrund einiger bedenken bzgl. Sicherheit dieses allerdings nicht immer gewünscht ist, da alle Keys die dort hinterlegt werden automatisch, für allen Projekte (auch für zukünftige) direkt verwendet werden können.
Nützliche Links:

Es trifft mich wie ein Blitz …

Java-Logo
… heute früh meldete Heise Security einen seit ca. neun Monaten bekannten Exploit, der sich als besonders kritisch einstuft.
Zu diesem Zeitpunkt war ich gerade in einem Meeting mit Bernd und bin fast aus allen Wolken gefallen, als Sebastian mit dieser Nachricht in der Tür stand.
Ich bot an dieser Meldung genauer auf den Grund zu gehen, da ich selber begeisterter Java Entwickler bin und mich wie vermutlich auch viele von euch direkt oder eben auch indirekt mit Java und dem erweiterten Stack tagtäglich beschäftige.
Im Netz kursiert seit dem 6. November der folgende Artikel, dessen Autor Herr Stephen Breen, sehr genau, fast schon spielerisch beschreibt, wie dieser Exploit denn genau funktioniert.
Er schreibt dort im wesentlichen über die in Java schon seit Version 1.1 verfügbare ‘Serializable’ Schnittstelle, die es dem Programmierer ermöglicht fertig instanziierte Java Objekte über das Netzwerk zu senden oder auch von Festspeichern zu lesen. Diese Klasse ist allerdings nur der kleinere Teil des Übels, genauer gesagt ist es die Methode “InvokerTransformer” der “Apache CommonCollections API” die hier über die “Java Reflections API” es einem möglichen Angreifer hier Kinderleicht macht seinen Schadcode auf dem Zielsystem zur Ausführung zu bringen.
Nun könnte man fast meinen das einen das ja nicht wirklich betrifft, da muss ich euch leider enttäuschen und das sogar berechtigterweise.
Folgende Szenarien um das Problem im wesentlichen zu konkretisieren:

  • Servlet Container sowie Application Server verwenden diese API, wie im Artikel zu lesen ist, auch um Cookies und HTTP Header zu lesen. Das ist im ersten Moment noch nicht so kritisch, nur werden heutzutage auch viele Cross-Site-Request-Forgery und andere Angriffe dazu verwendet die Systeme der Wahl erfolgreich zu attackieren.
    Ein Angreifer könnte versuchen über entsprechende HTTP Header mit Cookie Payload ein bösartiges Objekt seiner Wahl einzubetten, das wiederum wenn auf dem Ziel System einmal angekommen, im ersten Moment Zugriff auf die der dort laufenden Anwendung zu Verfügung stehenden Klassen nutzen kann. Hier ist es dann bereits ein leichtes dem Application Server bzw. ServletContainer einen separaten URL Context ( zum Beispiel unter http://application.yourdomain.com/nasty-little-exploit ) mit anderen Funktionen unterzujubeln. Et Voila der Schaden wäre bereits immens.
    Auch ein simpler Download als Injected Java Objekt könnte hier den Rest des Ziel Systems mit entsprechenden Schadcode über eine Art Bootstrap Job infizieren.
    Um dem vorher gehenden Beispiel noch einmal etwas Würze zu verleihen, einen bereits bestehenden URL Context einer großen Bank könnte so manipuliert werden, um Kundendaten abzugreifen. Auch hier wäre der Schaden nicht zu ermessen.
  • Die Software von Drittanbietern ist davon mit unter auch betroffen. Vor allem wenn sie die oben genannte Schnittstelle verwendet oder sogar muss. Hier sollte man schnell Handeln aber auf keinen Fall das Problem ignorieren. Allein anzunehmen das hier ja bereits verschlüsselte Kommunikation stattfindet, schütz vor diesem Exploit nicht.
  • Ich schlage ihnen daher vor, den Rat des Autors zu beherzigen und diese Schnittstelle aus der Apache CommonCollections API zu verbannen, allein die Nutzung der Application einzustellen um anschließend ein komplettes Refacturing der Anwendungen vorzunehmen verursacht vermutlich sehr hohe Kosten und ist hier mit der Gefahr verbunden sich einem weiteren Exploit zu schaffen, jedoch recht schnell geschehen. Schnelle Änderungen schaffen immer wieder neue Bugs und vermutlich auch neue noch unbekannte ZeroDay Vectoren.

Dem einen oder anderen von euch stellen sich hier vermutlich schon die Nackenhaare auf, daher wollen wir nun lieber über die Deeskalation bzw. möglichen Lösungen kümmern, was gilt es nun zu tun!?

  • Evaluieren ob die Apache CommonCollections API auf dem eigenen Systemen existiert.
  • Prüfen ob die eingesetzte Java Software von dieser Gebrauch macht.
    • Wenn dem so ist, sollte die Anwendung aus der DMZ entfernt werden, das blockieren der von außerhalb erreichbaren Ports genügt im ersten Moment bereits.
    • Wenn dem nicht so ist, dann Schwein gehabt.
  • Sofern die betroffenen Anwendungen ermittelt werden konnten, sollten folgende Punkte abgearbeitet werden.
    • Test der Anwendung in isolierter Umgebung ( Docker kann hierbei recht hilfreich sein ) mit der Apache CommonCollections API. Wobei vor Beginn die org/apache/commons/collections/functors/InvokerTransformer.class bereits aus der API entfernt sein sollte.
      Wenn es hier nichts zu beanstanden gibt und die Application auch ohne diese Schnittstelle zu laufen scheint, kann diese wieder in den Betrieb überführt werden.
    • Sollte die Anwendung nicht korrekt funktionieren, wird empfohlen diese unter Vorbehalt nur den eig. Mitarbeitern zur Verfügung zu stellen, sollte es sich bei der Anwendung allerdings, um eine des Kunden handeln, sieht es da schon etwas schwieriger aus, wobei sich vmtl. kein Kunde den damit einhergehenden Gefahren gerne ausgesetzt sieht.
      Hier sollte dem Kunden angeraten werden, die Application bis zu einem erfolgreichen Security Audit vom Netz zu nehmen.

Weitere Lösungsansätze sind derzeit noch nicht bekannt, wir versuchen euch aber entsprechend auf dem Laufenden zu halten.
Nützliche Links:

Link Inhalt
http://www.heise.de/security/meldung/Zero-Day-Alarm-fuer-viele-Server-mit-Java-2913605.html Heise Security Artikel
http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/ der Exploit im Detail
https://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections4/functors/InvokerTransformer.html Javadoc zum betroffenen Interface
https://github.com/frohoff/ysoserial das daraus entwickelte Framework für Penetration Tests
https://www.cvedetails.com/vulnerability-list/vendor_id-93/product_id-19117/Oracle-JRE.html Java CVE – Übersicht

Improved NodeJS Events durch Cluster …


… jeder von euch kennt das Problem, der Kollege kommt um die Ecke und möchte wenn möglich sofort, dass ein neues geiles Tools mit in den Infra Stack aufgenommen wird, gesagt getan.
In diesem Bespiel eine besonders cooles in NodeJS geschriebenes Dashboard für… lass es hier ein DockerManagement Tool sein. Dabei stößt man bei der großen Akzeptanz durch die Kollegen, auch auf einmal auf noch ganz andere Probleme (Stichwort: Performance Bottlenecks wie DDoS durch eigene Leute).
Hierbei könnte euch das NodeJS Modul Cluster behilflich sein, hier ist die Doku zu finden.
Cluster macht dabei nicht viel, es erweitert den NodeJS Stack insbesondere das Event Driven Modell von NodeJS ( so Arbeitet Google(s) v8 Engine ) um eine Art Interprocess Schnittstelle zu forked Child NodeJS Prozessen, die sich dabei Filesystem Elemente/Typen wie Sockets, Filedeskriptoren etc. teilen können und somit gemeinsam auf diesen operieren können.
Hier wollen wir eine schon bestehende Express Framework Anwendung mit einigen wenigen Zeilen Code um die Fähigkeit erweitern, dem System zur Verfügung stehenden CPU Cores effizienter ausnutzen zu können, damit sich die Events schneller abarbeiten lassen.
Ich werde hier allerdings nicht Express selber beschreiben, sondern setzte hier voraus das der Leser dieses Framework kennt. Wenn nicht könnt ihr die Infos unter diesem Link abrufen, so let’s beginn …

$ sudo -i                                  # <- da meine Workstation ein Ubuntu ist sollten wir zumindest was die Essentials sind kurz zu 'root' werden um diese Problemlos installiert zu bekommen
$ npm install express -g                   # <- installiert uns das Express Framework samt CLI Tools
express@4.13.3 /usr/lib/node_modules/express
├── escape-html@1.0.2
├── merge-descriptors@1.0.0
├── cookie@0.1.3
├── array-flatten@1.1.1
├── cookie-signature@1.0.6
├── utils-merge@1.0.0
├── content-type@1.0.1
├── fresh@0.3.0
├── path-to-regexp@0.1.7
├── content-disposition@0.5.0
├── vary@1.0.1
├── etag@1.7.0
├── serve-static@1.10.0
├── range-parser@1.0.2
├── methods@1.1.1
├── parseurl@1.3.0
├── depd@1.0.1
├── qs@4.0.0
├── on-finished@2.3.0 (ee-first@1.1.1)
├── finalhandler@0.4.0 (unpipe@1.0.0)
├── debug@2.2.0 (ms@0.7.1)
├── proxy-addr@1.0.8 (forwarded@0.1.0, ipaddr.js@1.0.1)
├── send@0.13.0 (destroy@1.0.3, statuses@1.2.1, ms@0.7.1, mime@1.3.4, http-errors@1.3.1)
├── type-is@1.6.9 (media-typer@0.3.0, mime-types@2.1.7)
└── accepts@1.2.13 (negotiator@0.5.3, mime-types@2.1.7)
$ npm install express-generator -g
/usr/bin/express -> /usr/lib/node_modules/express-generator/bin/express
express-generator@4.13.1 /usr/lib/node_modules/express-generator
├── sorted-object@1.0.0
├── commander@2.7.1 (graceful-readlink@1.0.1)
└── mkdirp@0.5.1 (minimist@0.0.8)
$ exit                                     # <- ab hier geht es ohne 'root' Rechte weiter
$ mkdir cool-app && cd cool-app            # <- Projekt Verzeichnis anlegen und in dieses wechseln
$ pwd                                      # <- vergewissern das wir uns auch in diesem wirklich befinden
/home/enzo/nodejsProjects/cool-app
$ express --git .                          # <- wir provisionieren uns unser Projekt from Scratch, dieses ist somit direkt Lauffähig ohne das wir einen Zeile Code schreiben müssen, haben hier leider keine Zeit zu 😉
   create : .
   create : ./package.json
   create : ./app.js
   create : ./.gitignore
   create : ./public
   create : ./routes
   create : ./routes/index.js
   create : ./routes/users.js
   create : ./views
   create : ./views/index.jade
   create : ./views/layout.jade
   create : ./views/error.jade
   create : ./bin
   create : ./bin/www
   create : ./public/javascripts
   create : ./public/images
   create : ./public/stylesheets
   create : ./public/stylesheets/style.css
   install dependencies:
     $ cd . && npm install
   run the app:
     $ DEBUG=cool-app:* npm start
$

Ab hier können wir das ganze mal kurz testen, um uns zu vergewissern das die Anwendung auch läuft ...

$ npm start
> cool-app@0.0.0 start /home/enzo/nodejsProjects/cool-app
> node ./bin/www

Nicht wundern die Applikation bleibt im Vordergrund hängen, was ist Ok ist, somit können wir diese schneller terminieren und relaunchen. Weiter geht es mit einem Test im Browser, die Anwendung lauscht standardmäßig am Port 3000, somit rufen wir hier einmal http://localhost:3000 auf und lassen uns überraschen was da so schönes kommt ...

Geil es läuft also, nun gut machen wir das ganze mit Cluster noch skalierbarer, let's go ...
Öffnet hierzu im Projekt Verzeichnis einmal die bin/www Datei, diese stellt laut package.json unseren Eintrittspunkt in die Anwendung dar, wir kopieren uns diese als Backup weg bevor wir anfangen hier Änderungen vorzunehmen.
Kommentiert bitte folgende Zeilen einmal aus ...

/**
 * Get port from environment and store in Express.
 */
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
 * Create HTTP server.
 */
var server = http.createServer(app);
/**
 * Listen on provided port, on all network interfaces.
 */
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

... nun fügt ihr ab Zeile 10 bitte folgendes hinzu ...

// cluster requirements
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if( cluster.isMaster ) {
  for( var i = 0; i < numCPUs; i++ ) {
    cluster.fork();
  }
  cluster.on( 'listening', function( worker ){
    console.log( 'worker ' + worker.process.pid + ' is now listen for incoming connections ... ' );
  });
  cluster.on( 'exit', function( worker, code, signal ) {
    console.log( 'worker ' + worker.process.pid + ' died' );
  });
} else {
    // Workers can share any TCP connection
    // In this case it is an HTTP server
    /**
    * Get port from environment and store in Express.
    */
    var port = normalizePort(process.env.PORT || '3000');
    app.set('port', port);
    /**
    * Create HTTP server.
    */
    var server = http.createServer(app);
    /**
    * Listen on provided port, on all network interfaces.
    */
    server.listen(port);
    server.on('error', onError);
    server.on('listening', onListening);
}

.. jetzt sollte das ganze auch schon funktionieren, probieren wir es doch einmal aus.

$ npm start
> cool-app@0.0.0 start /home/enzo/nodejsProjects/cool-app
> node ./bin/www
worker 31979 is now listen for incoming connections ...
worker 31974 is now listen for incoming connections ...
worker 31985 is now listen for incoming connections ...
worker 31996 is now listen for incoming connections ...
GET / 304 840.784 ms - -
GET /stylesheets/style.css 304 31.416 ms - -

Jetzt könnte man denken das sich hier nichts geändert hat, dem ist aber nicht so, der Beweis ist in der Prozess Tabelle zu finden, gucken wir doch kurz einmal hinein ...

$ ps auxf | grep node
enzo     31969  0.1  0.4 901264 33004 pts/7    Sl+  14:47   0:00          |   |       \_ node ./bin/www
enzo     31974  0.1  0.4 901256 32324 pts/7    Sl+  14:47   0:00          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www
enzo     31979  0.4  0.6 946192 47560 pts/7    Sl+  14:47   0:01          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www
enzo     31985  0.1  0.4 902668 32736 pts/7    Sl+  14:47   0:00          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www
enzo     31996  0.1  0.4 901256 32168 pts/7    Sl+  14:47   0:00          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www

Whoop whoop, 4 neue NodeJS Prozesse die hier ihre Arbeit verrichten, somit lassen sich auch die beschäftigsten Web Anwendungen wieder beschleunigen.
Das ist aber nur der Anfang wie sich NodeJS Applications aller Art verbessern lassen, für weiter Themen habe ich heute allerdings keine Zeit daher heben wir uns den Rest einfach für ein anderes mal auf.
Ich wünsche euch hiermit noch viel Spaß, ich hoffe ihr habt nun mehr Lust auf NodeJS bekommen.

check_smartvalues Release … YEAH!!!

Endlich bin ich dazu gekommen, den schon im Post vom letzten Sommer angekündigten Check für S.M.A.R.T. -Werte zu veröffentlichen.
Ich hatte es ja schon angedroht, nun mache ich es wahr. 😉
Wir haben diesen Check nun schon ein gutes Jahr im Betrieb und er liefert seine Daten von daher kann ich ihn nur wärmstens empfehlen.
Bilder gibt es dieses Mal auch zu sehen, lasst sie am besten einfach mal auf euch wirken.
Wenn der Eine oder Andere von euch noch weitere tolle Ideen/Vorschläge hat, dann lasst es uns wissen. Wir lieben Monitoring, von daher stehen die Chancen recht gut, dass wir noch mehr umsetzen wollen.
Ich schrieb ja auch schon, dass die freundlichen Kollegen der Thomas Krenn AG auch ein Plugin für das Ermitteln der S.M.A.R.T. -Werte gebaut haben, dieses erfüllt im Wesentlichen auch die gleichen Aufgaben. Ich wollte das Ganze aber doch noch ein wenig toppen.
Hier ein paar Beispiele wie es aufzurufen ist:

# cd /path/to/check/smartvalues
# ./check_smartvalues -db check_smartvalues.db.json -c check_smartvalues.db.json -s -d 'megaraid,22 /dev/sda'
OK: [ 22 OK ] - [ 0 WARNING ] - [ 0 CRITICAL ] - [ 0 UNKNOWN ] in 0.163578987121582ms ( for details pls take a look in longoutput )
OK: on LSI MegaRAID - [ DeviceID 22 ] - #5 - Reallocated_Sector_Ct is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #9 - Power_On_Hours is [ 100 ] - [ w: 200, c: 300 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #12 - Power_Cycle_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #170 - Available_Reserved_Space is [ 100 / 010 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #171 - Program_Fail_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #172 - Erase_Fail_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #174 - Unexpected_Power_Loss is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #183 - Runtime_Bad_Block is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #184 - End-to-End_Error is [ 100 / 090 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #187 - Reported_Uncorrect is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #190 - Airflow_Temperature_Cel is [ 31 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #192 - Power-Off_Retract_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #199 - UDMA_CRC_Error_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #225 - Host_Writes is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #226 - Timed_Workload_Media_Wear is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #227 - Timed_Workload_Host_Read/Write _Ratio is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #228 - Power-off_Retract_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #232 - Available_Reservd_Space is [ 100 / 010 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #233 - Media_Wearout_Indicator is [ 043 ] - [ w: 35, c: 25 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #241 - Total_LBAs_Written is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #242 - Total_LBAs_Read is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #249 - Total_NAND_Writes is [ 100 ]

oder mit mehr als nur einer Platte …

# ./check_smartvalues -db check_smartvalues.db.json -c check_smartvalues.db.json -s -d 'megaraid,22 /dev/sda' -d 'megaraid,21 /dev/sda'
OK: [ 44 OK ] - [ 0 WARNING ] - [ 0 CRITICAL ] - [ 0 UNKNOWN ] in 0.18438987121582ms ( for details pls take a look in longoutput )
OK: on LSI MegaRAID - [ DeviceID 22 ] - #5 - Reallocated_Sector_Ct is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #9 - Power_On_Hours is [ 100 ] - [ w: 200, c: 300 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #12 - Power_Cycle_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #170 - Available_Reserved_Space is [ 100 / 010 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #171 - Program_Fail_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #172 - Erase_Fail_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #174 - Unexpected_Power_Loss is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #183 - Runtime_Bad_Block is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #184 - End-to-End_Error is [ 100 / 090 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #187 - Reported_Uncorrect is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #190 - Airflow_Temperature_Cel is [ 31 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #192 - Power-Off_Retract_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #199 - UDMA_CRC_Error_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #225 - Host_Writes is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #226 - Timed_Workload_Media_Wear is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #227 - Timed_Workload_Host_Read/Write _Ratio is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #228 - Power-off_Retract_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #232 - Available_Reservd_Space is [ 100 / 010 ]
OK: on LSI MegaRAID - [ DeviceID 22 ] - #233 - Media_Wearout_Indicator is [ 043 ] - [ w: 35, c: 25 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #241 - Total_LBAs_Written is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #242 - Total_LBAs_Read is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #249 - Total_NAND_Writes is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #5 - Reallocated_Sector_Ct is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #9 - Power_On_Hours is [ 100 ] - [ w: 200, c: 300 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #12 - Power_Cycle_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #170 - Available_Reserved_Space is [ 100 / 010 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #171 - Program_Fail_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #172 - Erase_Fail_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #174 - Unexpected_Power_Loss is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #183 - Runtime_Bad_Block is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #184 - End-to-End_Error is [ 100 / 090 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #187 - Reported_Uncorrect is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #190 - Airflow_Temperature_Cel is [ 32 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #192 - Power-Off_Retract_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #199 - UDMA_CRC_Error_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #225 - Host_Writes is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #226 - Timed_Workload_Media_Wear is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #227 - Timed_Workload_Host_Read/Write _Ratio is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #228 - Power-off_Retract_Count is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #232 - Available_Reservd_Space is [ 100 / 010 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #233 - Media_Wearout_Indicator is [ 041 ] - [ w: 35, c: 25 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #241 - Total_LBAs_Written is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #242 - Total_LBAs_Read is [ 100 ]
OK: on LSI MegaRAID - [ DeviceID 21 ] - #249 - Total_NAND_Writes is [ 100 ]

und hier das Ergebnis im neuen Icinga Web 2 …
sdd22-smart-values
 
Nützliche Links:

powerline-shell

powerline-shell
Hi folks,
ich habe letztens bei meinem Kollegen Mr. Frog ein neues Bling-Bling entdeckt The Mighty Powerline-Shell die mir besonders gut gefallen hat, ich war so angefixt das Ich mir einbildete das auch haben zu müssen, gesagt getan.
Die Powerline-Shell ist richtig Gut, da Sie als Segmentiertes ‘self contained’ Python-Script folgende Features abdeckt.

  • Ihr seht egal ob Git, SVN, Mercurial o. Fossil immer was gerade Sache ist
  • wenn eure Pfade auf einer Zeile zu lang werden, dann werden Sie gekürzt ohne relevante Information zu verlieren
  • viel Buntes für den Kreativen Ops/Dev ( Colored Themes )
  • auch werden euch Rückgabe werte des letzten Befehls aus eurer Shell ungleich 0 zurückgegeben
  • wenn Ihr euch per SSH auf entfernte Systeme verbindet, dann wird auch dies durch ein Schloss Symbol kenntlich gemacht
  • wenn das aktuelle Verzeichnis nicht mit euren Rechten beschrieben werden darf, wird dies auch durch ein Schloss Symbol wiedergegeben
  • Sie kann auch den Title eures TerminalEmulator mit user@host:/path Einträgen umschreiben
  • zeigt auch Änderungen an der Umgebung an ( Virtual Environment )
  • die aktuelle Zeit ist nun auch mit am Start ( Segment wurde von mir eingeführt, da ich dieses Feature für mein Daily benötige )
  • zeigt auch laufende Hintergrund Jobs an ( Shell forks )
  • die Features sind leicht zu erweitern ( Segmente werden in Python geschrieben )

Die Powerline-Shell ist auch sehr benutzerfreundlich in etwa 3 Schritten eingerichtet.

cd ~ && mkdir git && cd git
git clone https://github.com/powerline/fonts.git powerline-shell-fonts
git clone https://github.com/lenrico/powerline-shell.git
./powerline-shell-fonts/install.sh
./powerline-shell/install.py
vi ~/.bashrc

Noch fix den Prompt auf die Powerline-Shell umbiegen. 😉

function _update_ps1() {
	export PS1="$(~/powerline-shell.py $? 2>> /dev/null)"
}
export PROMPT_COMMAND="_update_ps1; $PROMPT_COMMAND"

Und einen der neu installierten Fonts mit dem ‘Powerline’ Suffix wählen, fertig.
Hier noch Bilder “weil Bilder mehr als tausend Worte …” naja ihr wisst schon.
github-lenrico-powerline-shell
Links:
https://github.com/lenrico/powerline-shell
https://github.com/Lokaltog/powerline-fonts
 

Cubietruck ( Entertainment in 1080p )

Was macht der Netways-Mitarbeiter, wenn er abends nach Hause kommt?
Er schaltet sein Entertainment-System ein und legt klassische Musik auf …
… Klassik? Nein nicht wirklich, das mit dem Entertainment System ist allerdings wahr.
Ich möchte euch hier etwas über mein Entertainment-System berichten, dem Cubietruck, einem leistungsfähigen Ersatz für den RaspberryPi.
cubietruck-hand
Zudem haben Netways-Mitarbeiter unter anderem noch andere Anforderungen an solch ein Spielzeug. 🙂 Hier mal einige mögliche Anwendungsthemen:

  • als MPI Cluster ( ja so Verrückte gibt es auch hier bei Netways 😉 )
  • als WLAN AP ( oder Bluetooth FileShare )
  • als Network Monitoring TAP ( für die Traffic Analyse im heimischen Netzwerk – aber auch in Firmennetzen ganz hilfreich )
  • als NAS ( mit Samba und NFS als Shared-Storage für Backup von Fotos, Dokumenten etc. … )
  • als Mobile Computer ( zum Surfen, Schreiben, Programmieren sogar mit dem heimischen Fernseher )
  • als Computer zum Lernen ( für die Kleinen aber auch ganz Großen )
  • als Home Entertainment-System ( mit KODI ehemals XBMC, wahrscheinlich das, was sich viele als Ersatz oder gar Ergänzung zu einer Set-Top Box wünschen )

Mit der Installation von Ajenti oder einer der anderen WebGUI’s ( OpenPanel, Webmin ) ist es möglich das Gerät vollständig über ein Webinterface zu steuern, in Kombination mit OwnCloud und MySQL/MariaDB ist das System eine vollwertige CloudSharing Lösung.
Auch LXDE oder gar XFCE stressen die Allwinner A20 CPU nicht sonderlich. Somit ist das System auch als Lerncomputer für die Kids ganz gut geeignet (es muss nicht immer teure Hardware sein) .
Die Bastler unter euch haben bestimmt auch ganz exotische Vorstellungen bzgl. Networking. So ist es möglich, den Cubietruck auch als WLAN AP einzusetzten. Entweder händisch mit OpenWRT oder auch ganz bequem über die WebGUI mit DD-WRT. Die ganz Pfiffigen unter euch basteln sich das Ganze auf Basis der verfügbaren Distributionen in wenigen Minuten selber zusammen.
cubietruck-case
Viele von euch haben dieses System vermutlich bereits für sich erkannt, und Fragen sich bestimmt „Warum berichtet er uns hier den über ein Gerät das bereits ca. ein halbes Jahr alt ist?“, und die Antwort ist „Kinderkrankheiten“, jedes System bzw. OS ist in der Phase seiner Entwicklung noch recht verbugged, das betraf auch das Cubieboard3. Der Cubietruck ist momentan der beste Ersatz für den RaspberryPi, wenn es um Leistung und Ausstattung geht.
Hier mal die Hardware Ausstattung des Cubieboard3 ( aka Cubietruck ):

  • AllWinnerTech SOC A20 ARM® Cortex™-A7 Dual-Core ARM®
  • 2GB RAM DDR3
  • VGA & DVI 1080P
  • 10/100/1000Mbit Ethernet
  • Wifi+BT ( in einem Chip )
  • SATA 2.0 Port für 1.8/2.5′ HDDs ( auch 3.5′ HDDs sind möglich brauchen allerdings einen externen Strom Anschluss )
  • MicroSDHC Slot sowie NAND 4GB ( mit vorinstalliertem Android )
  • 2 x USB 2.0
  • 1 x Infrarot
  • 1 x 3.5 klinke
  • 1 x LED ( diese könnt Ihr auch selber ansteuern )
  • 1 x SPDIF
  • 1 x Power DC5V@2.5A ( ein altes Smartphone USB-Ladegrät reicht hier aus )
  • 1 x 54 Pin
  • 1 x JTAG & UART over USB
  • Board Abmessung 11 x 8 cm
  • mitgeliefert werden Plexiglass und Schrauben ( als Provisorisches Gehäuse ganz nett anzusehen )

cubietruck-overview
Die folgenden Links könnten für den Einstieg ganz Hilfreich sein.

Sonstiges:

 

Galera Clustering

Viele von Euch kennen es bestimmt schon, das Project Galera. Dieses vereint die wsrep API mit MySQL bzw. dessen Fork MariaDB. Zum aktuellen Zeitpunkt werden schon InnoDB und die XtraDB – Storage Engine unterstützt. Letzteres ist eine InnoDB-Erweiterung und wird von Percona entwickelt .

Galera-Cluster-logo-1024x195

Der Galera Cluster bringt folgende Features/Benefits mit:

  • Multi-Master schon von Haus aus
  • Synchrone Replication kein Datenverlust mehr auch keine Slave-Lags mehr (Boa wie mich das immer wieder nervt)
  • Eng gekoppelt Alle Knoten haben grundsätzlich denselben Status, keine Daten mehr die auseinander laufen
  • Multi-threaded Slave für bessere Performance der Nutzlast
  • Keine Master-Slave Failover Operationen nötig oder die Notwendigkeit eine virtuelle IP binden zu müssen
  • Hot Standby keine Downtimes während des Failover (denn es gibt keinen Failover mehr)
  • Automatic Node Provisioning kein manuelles Eingreifen mehr um Knoten in den Cluster zu bringen, die Daten werden automatisch auf den neuen Knoten repliziert
  • Supports InnoDB bald auch MyISAM (ist noch experimentell)
  • Transparent zur Application benötigt in Kombination mit GLB (oder HAproxy) keine Änderungen an der Applikation
  • Kein Aufspalten von Read und Write Operationen nötig (einfach Feuer auf das Ding 😉 ).

Galera ist somit die Lösung für Unternehmungen die ein hohes Aufkommen an Schreib- und Lese -Operationen in ihren Datenbanken erwarten. Die Main “Use Cases” für den Betrieb des Galera Cluster sind eben kurz und gut, Skalierung der Schreib-Operationen, entkoppeln von Latenz Killern (wie zB. lange laufende Queries).
Die Entwickler des Forks MariaDB haben diese vielfältigen Möglichkeiten erkannt und bieten auf ihren Seiten Anleitungen zum Betrieb so eines Basic Setups an. Ebenfalls werden dort fertige Pakete für die Installation auf alle Major Linux Distributionen angeboten, somit fällt auch schon mal das Kompilieren weg.
Für das Setup können zwei Loadbalancing-Produkte zum Einsatz kommen: Zum einen der schon etwas in die Jahre gekommene (aber immer noch sehr beliebte) HAproxy und zum anderen GLB (Galera LoadBalancer), der eigens für Galera, aber außerhalb des Projekts entstanden ist. Wir bevorzugen für unsere Setups meist den GLB da dieser auch während der Laufzeit (wenn nötig auch automatisiert durch Skripte) konfiguriert bzw. gesteuert werden kann. Änderungen können somit im laufenden Betrieb und auch unter Last problemlos vorgenommen werden. Wenn es dann doch mal knapp wird, kann man im Betrieb ganz einfach einen weiteren Knoten hinzufügen 🙂

Nicht noch ein S.M.A.R.T. Check …

… es gibt doch schon so viele davon! JA das dachte sich mein Kollege der Achim Ledermüller auch und bat mich doch vor ca. Zwei Wochen, ich solle Ihm einen Check für SSD Platten (für sein Ceph-Projekt) in Unser Monitoring einbauen. Was grundsätzlich mit Checks von der monitoringexchange.org Platform abgedeckt wird hat meinen Kollegen nicht zufriedenstellen können, seine Anforderungen lauteten wie folgt:

S.M.A.R.T. Werte der SSDs zuverlässig überprüfen.
– Mindestens MWI.
– Recherchieren welche Werte sonst aussagekräftig sind!

Die Freunde von Thomas-Krenn haben sich wohl das Gleiche gedacht und auch so ein Plugin gebaut. Da wir aber nur hier bei Uns ziemlich pingelig sind was den Umfang so wie Portabilität an Software (seien es auch nur Plugins) angeht, habe ich mich kurzerhand dazu entschieden ein neues Plugin auf Basis des schon Vorhanden zu schreiben.
Lange rede kurzer Sinn, “check_smartvalues” wurde geboren und deckt eigentlich alles ab, was man sich bei anderen S.M.A.R.T. -Checks so Wünscht und noch viel mehr ( mehr möchte Ich allerdings noch nicht verraten 🙂 ).
Da ich derzeit einen großen namhaften Kunden in Bezug auf das am Ende des Jahres kommende Icinga2 & Icingaweb2 betreue, wollte ich auch Euch die Ansicht der neuen Web-UI nicht vorenthalten. Hier mal ein Bild …

lx-ssd-smart-icingaweb2-longoutput

Der Longoutput der Plugins im neuen Icingaweb2, mit hübschen Kuchen Diagrammen.

Im derzeit noch vielerorts Installiertem “inGraph” für Icingaweb1, sieht die ganze Sache natürlich auch sehr schön aus

mwi

Der “Media Wearout Indicator” hier im “inGraph-Icingaweb1” über eine Zeitschiene von einem Monat mit einem Scalefactor bei 90% ( sonst würde man halt nix Sehen ).


und weil ich Persönlich ein großer Fan des neuen Icingaweb2 bin, und diese HTML5 Kuchendiagramme einfach liebe, hier nochmal eine Nah-Ansicht des “Media Wearout Indicator” …
mwi-icinga2

hier der “Media Wearout Indicator” in Groß, man sieht auch sehr schön, das die Platte (eine Intel 530 SSD hinter dem MegaRaid LSI mit DeviceID 22 ), nach eben nur 4 Wochen Lifetime doch schon sehr geschruppt wurde.


Das Plugin ist derzeit noch im Testing, bei Uns hier im Monitoring allerdings schon mal Live da mein Kollege eben auch sehr für Graphen zu begeistern ist. Es bezieht seine Daten sowie auch die Konfiguration für Schwellewerte aus einer JSON-Datenbank, das ganze sieht dann in etwa so aus …
lx-ssd-database
Sobald den die Letzten Tests abgeschlossen sind werden ich den Check auf der neuen Icinga Exchange Plattform zum Download anbieten.
Im übrigen, das Plugin ist in seiner Grundfunktion schon als Multicheck ausgelegt, so viel möchte ich an dieser Stelle nun doch schon mal verraten. 😉
Macht euch auf was gefasst …