Infrastruktur, Monitoring und Softwareverteilung


An sich klingt es recht einleuchtend: Das Ziel des Aufbaus einer Daten-Analyse-Plattform ist es, eine Plattform zur Analyse von Daten zur Verfügung zustellen.

Hier stellt sich natürlich direkt die erste Frage: Welche Daten sind vorhanden und auf welche Art sollen diese analysiert werden? Beide Teilaspekte sind ausschlaggebend für die Auswahl der Hard- und Softwarekomponenten.

Als kurzer Reminder: Bitte bedenken Sie, dass es sich nicht lohnt, eine Big Data Plattform aufzubauen, wenn Sie keine Big Data haben. Ja, natürlich klingt es gut zu sagen, dass man einen Hadoop-Cluster betreibt. Aber:

  • Sie müssen diesen eben “betreiben” und
  • es gibt enorm viele Daten(sätze), die sehr gut in den Arbeitsspeicher passen und die sich über gute und kostengünstige Alternativen analysieren lassen (siehe: Datenanalyse ohne Hadoop-Cluster)

Aber nun wollen wollen wir uns um den Aufbau der Appliance kümmern, denn unsere Daten sind enorm groß und enorm volatil. Die Details der Daten werden wir uns in einem späteren Blog anschauen.

Aufbau der Appliance-Infrastruktur

Hardware

Zu Beginn sollten wir uns Gedanken gemacht haben, ob wir lieber einzelne, kleinere Systeme (z.B. Intel NUCs) erwerben oder ein großes System zur Verwaltung von virtuellen Maschinen nutzen möchten. Die Nutzung einer Cloud kommt für uns erst ein Mal nicht in Frage, da wir uns dem Thema Aufbau einer Appliance von allen Seiten aus nähern möchten.

Einzelne, kleinere Systeme haben den Vorteil, dass man mit wenigen starten und diese nach und nach erweitern kann. Da wir allerdings neben dem Hadoop-Cluster auch Systeme für die Datenflüsse und die Daten-Analyse benötigen, müssten wir gleich zu Beginn wenigstens 6 erwerben (1 Hadoop-Cluster-Master, 3 Hadoop-Cluster-Member, 1 Data-Flow- und 1 Data-Analytics-System). Die Gesamtkosten dieser Systeme kommen allerdings schon sehr an die Kosten für ein leistungsfähiges Multi-Core-System, so dass wir uns hier für letzteres entscheiden, auch und vor allem um verschiedene Konfigurationen (CPU, RAM, DISK) ausprobieren zu können. Hier eine mögliche Konfiguration:

  • CPU: AMD Threadripper 1950x mit 16 nativen Kernen und 32 Threads
  • GPU: MSI GeForce GTX 1050 Ti Gaming X 4 GB (kann später für die Analyse genutzt werden)
  • RAM: Corsair 128 GB (8 x 16 GB)
  • DISK: Samsung 960 Pro NVMe SSD, Western Digital Purple HDD

Auf weitere Komponenten des Systems, wie beispielsweise Mainboard und Kühlung, gehen wir hier im Detail nicht näher ein, da es für den Aufbau der Appliance nicht relevant ist.

Ein Hadoop-Cluster im Stand-Alone-Modus auf einer/dieser leistungsfähigen Hardware zu betreiben, ist wenig sinnvoll, daher bauen wir nun die einzelnen Cluster-Member virtuell auf und haben dabei die Möglichkeit, einzelne Systeme später mit mehr oder weniger CPUs und Speicher auszustatten, um zu den verschiedenen Konfigurationen Erfahrungen zu sammeln.

Virtualisierung

Zur Virtualisierung stehen uns unterschiedliche Software-Komponenten zur Verfügung, die je nach Host-Betriebssystem ihre Stärken ausspielen. Um hier das Host-System für die virtuellen Umgebungen ein wenig in den Hintergrund zu drängen, wählen wir eine Software, die für viele Betriebssysteme zur Verfügung steht und sich zusätzlich sehr gut über die Kommandozeile konfigurieren läßt: Virtualbox von Oracle. Somit kann die Appliance sehr gut unter Microsoft Windows oder auch Linux als Host aufgebaut werden. Wichtig bei der Auswahl des Host-Betriebssystems ist nur die Unterstützung der NVIDIA Grafikkarte von MSI, da wir zur Datenanalyse später ggf. die vielen Rechenkerne der Grafikkarte verwenden möchten. Das wiederum schränkt das Betriebssystem des Hosts mehr ein als die Auswahl der Virtualisierungssoftware, denn eine einfache Nutzung der NVIDIA-CUDA-Software ist aktuell eher für Ubuntu-Linux (16.04 LTS) und Microsoft Windows 10, als für CentOS oder andere Linux-Derivate verfügbar.

Da die virtuellen Umgebungen, wie auch die Virtualisierungssoftware, betriebssystemunabhängig sind, ist es sogar möglich, die Appliance mit mehreren Host-Betriebssystemen aufzubauen und je nach Anforderung (oder Zeit und Lust) entsprechend umzuschalten.

Hinweis: Die Virtualisierung hätte auch mit Docker durchgeführt werden können. Ich habe mich für Virtualbox entschieden, da ich im Besonderen auf die Konfiguration und Verteilung der Software unter einem realen Betriebssystem eingehen wollte, so wie wir es, wenn Sie keine Appliance verwenden möchten, auch mit normalen PC-Systemen durchführen würden.

Cluster-Member

Für die einzelnen Cluster-Member müssen wir uns nun überlegen, wie wir diese (vorerst) konfigurieren, um die Speicherung der Daten und die darauf aufbauenden Analysen sinnvoll zu verteilen.

Als Best Practice für einen kleinen Cluster hat sich folgender Aufbau als sinnvoll erwiesen:

  • für die Verwaltung: 1 Master als Namenode für HDFS und als HMaster für HBase (2 CPU-Cores, 4 GB RAM und 20 GB Disk sind zu Beginn ausreichend)
  • für die Verteilung der Daten und -Analysen: 3 Worker als Datanode für HDFS, als Regionserver für HBase und als Drillbit-Daemon für Drill (je 4 CPU-Cores, 8 GB RAM und 128 GB Disk)
  • für die Datenflüsse: 1 System, das als Master und Worker für Apache NiFi fungiert (4 CPU-Cores, 8 GB RAM und 64 GB Disk)
  • als Kommunikationsmedium für die einzelnen Arbeitsschritte: 1 System, das als Broker unter Apache Kafka dient (4 CPU-Cores, 4 GB RAM und 64 GB Disk)

Somit kommen wir in Summe, für das erste Setup, auf insgesamt 6 Systeme mit 22 CPU-Cores, 48 GB RAM und 532 GB Disk. Da uns in der Appliance 16 CPU-Cores mit 32 Threads, 64 GB RAM und 3GB (1GB SSD + 2GB HDD) Disk zur Verfügung stehen, haben wir noch ein wenig Luft für Erweiterungen. Die Nutzung des Clusters wird uns später zeigen, ob die Konfiguration so hinreichend gewählt ist.

Bereitstellung einer virtuellen Umgebung

Um die einzelnen Cluster-Member nun als virtuelles System bereitzustellen, ist es erst ein mal notwendig, sich für eine Betriebssystem zu entscheiden. Die gute Nachricht zu Beginn: Aus der Liste der etablierten Linux-Distributionen (und Linux muss es schon sein) können wir frei wählen, da die Software, die wir verwenden, zum großen Teil “nur” auf einer lauffähigen JAVA-Umgebung aussetzt. Wir müssen somit nicht erst prüfen, ob der Paketmanager der Distribution die korrekte = aktuelle Version unserer Software bereitstellt.

Nun leider die schlechte Nachricht: Es gibt soooo viele etablierte Linux-Distributionen. Und eben so viele Vorlieben und gute Gründe, die eine Distribution der anderen vorzuziehen.

Meine Schwerpunkte bei der Auswahl für die Cluster-Member lagen allerdings im offiziellen Support der Distribution bei großen Hardware-Anbietern (um ggf. später die Umgebungen problemlos übertragen zu können) und in der Langzeit-Unterstützung der Distribution bei Software-Upates. Sehr bekannt ist die bereits zuvor genannte Distribution Ubuntu in der Version 16.04 LTS, sowie CentOS als freier Klon der Red-Hat-Distritution und Debian, die als Basis für Ubuntu & Co. dient. Da ich Debian bereits auf einen anderen Cluster verwende und Ubuntu 16.04 LTS als Host für die Appliance zum Einsatz kommt, habe ich CentOS verwendet, um möglichst viel beim Aufbau der Appliance lernen zu können.

Die Installation von CentOS als virtueller Maschine unter VirtualBox ist hinreichend unspektakulär und wurde bereits ausreichend in anderen Blogs und Videos beschrieben. Suchen Sie in der Internet-Suchmaschine Ihrer Wahl einfach nach install centos 7 on virtualbox und Sie werden sogar Video-Anleitungen hierzu finden. Die einzig wichtigen Punkte nach der Installation des Betriebssystems sind die korrekte Vergabe einer IP-Adresse und die Zuweisung des gewünschten Hostnames. Damit die virtuelle Maschine als eigenständige Umgebung im Netzwerk identifiziert wird, konfigurieren wir den Netzwerk Adapter (network adapter) als Bridged Adapter (attached to: Bridged Adapter) und wählen als Basis für diesen Adapter die Netzwerkkarte des Hosts.

Die Vergabe einer IP-Adresse geschieht in meinem Netzwerk über einen DHCP-Server, der glücklicherweise auch gleich bei Zuordnung der MAC-Adressse einen DNS-Eintrag vorhält.

Der Hostname bei CentOS wird nach erfolgreicher Anmeldung wie folgt gesetzt:

sudo hostnamectl set-hostname "meinHostname" --static


Die erste Maschine nutzen wir als Vorlage - ich habe sie analyticsTemplate genannt, um aus dieser die verschiedenen Cluster-Member zu erzeugen. In VirtualBox geht das über die Auswahl der VM, einem Klick mit der rechten Maustaste bei Auswahl Clone. Die Tastenkombination zur Ausführung dieser Funktion ist ctrl + o. Bitte wählen Sie in dem angezeigten Dialog auch Reinitialize the MAC address of all network cards aus, damit der DHCP-Server durch die neue MAC-Adresse eine neue Zuordnung zu einer IP-Adresse und ggf. des internen DNS-Eintrags vornehmen kann.

Auf diesem Wege legen wir dann folgende virtuellen Maschinen an:

  • analyticsMaster
  • analyticsWorker1
  • analyticsWorker2
  • analyticsWorker3
  • analyticsBroker1
  • analyticsDataflow1

Überwachung der Cluster-Member

Um gleich zu Beginn eine gute Basis für einen kontrolliert lauffähigen Cluster zu haben, binden wir die neuen Cluster-Member direkt in das System-Monitoring unserer Netzwerk-Infrastruktur ein.

Sie haben sich bisher mit dem Thema Monitoring noch nicht beschäftigt? Dann möchte ich Ihnen zumindest diese vier Systeme zur weiteren Berücksichtigung nennen.

Nagios ist sicherlich der Urvater des System-Monitoring in neueren (also nicht Mainframe-) Umgebungen. Viele andere Systeme orientieren sich daran. Ich habe mich allerdings für Zabbix entschieden, da mir auf der einen Seite ein schlanker Agent auf den Systemen wichtig war (da ich auch weniger leistungsfähige Systeme überwachen möchte, wie beispielsweise einen Raspberry Pi) und auf der anderen Seite eine einfache Abfrage beliebiger Metriken auf dem Monitoring-Client im Fokus stand. Der Zabbix-Agent benötigt kaum Arbeitsspeicher und erzeugt wenig Systemlast. Und er lässt sich einfach über die Agent-Konfiguration um eigene Skripte erweitern. Hinzu kommt eine sehr gute JMX-Überwachung, was im Hadoop-Umfeld sehr hilfreich ist, da die meisten Hadoop-Komponenten auf JAVA aufsetzen.

Softwareverteilung auf die Cluster-Member

Die beiden Themen Big Data und Cloud gehören nicht zwingend zusammen, werden aber doch häufig gemeinsam genannt. Wird eine Anwendung als Cloud-Lösung konzipiert, so ist es nicht nur sehr wichtig, dass die einzelnen Systeme effizient miteinander kommunizieren. Es muss auch kurzfristig möglich sein, bestehende Cloud-Instanzen zu erweitern oder zu reduzieren.

Um dieses wiederum effizient durchführen zu können, wurde sehr schnell der Begriff Infrastructure as Code erzeugt, der bedeutet, dass die Bereitstellung einer Laufzeit-Umgebung nicht mehr aufwändig per Hand, sondern automatisiert über Konfigurationsdateien stattfindet, die man dann sogar in einem Versionierungssystem (wie beispielsweise GIT oder Mercurial) verwalten kann.

Unsere virtuellen Maschinen in der Appliance sind, mit etwas Abstand betrachtet, auch nichts anderes als Laufzeit-Umgebungen eines Cloud-Anbieters: Unsere Appliance ist quasi eine Cloud. Was uns als Übergang zur Softwareverteilung dienen soll.

Wie bereits erwähnt, basieren viele Hadoop-Komponenten auf JAVA und sind somit nach Bereitstellung einer JAVA-Runtime theoretisch lauffähig. Theoretisch lauffähig, da für den einwandfreien Betrieb der Komponente noch einige (wenige) Konfigurationen vorgenommen werden müssen.

Da wir nun bereits 6 Cluster-Member (und eine Template VM) haben, würde es bedeuten, wir müssten auf den 6 virtuellen Maschinen JAVA installieren. Sie könnten einwenden, dass wir JAVA auch zuvor in der Template VM hätten installieren können, was uns somit von der Installation auf 6 Maschinen befreit hätte. Das ist korrekt, verlagert das “Problem” allerdings nur ein wenig im Ablauf.

Wenn wir uns nun vorstellen, dass wir nicht mit 6, sondern mit 100 virtuellen Maschinen arbeiten, ist jedem gleich klar, dass wir eine andere Lösung benötigen.

Und diese Lösung heißt rsync und/mit ansible und funktioniert folgendermaßen: Um unabhängig vom Host der bisher 6 virtuellen Umgebungen zu sein, bauen wir uns eine 7. Umgebung als analyticsDevelopment auf und konfigurieren diese ebenso wie die 6 VMs zuvor (Network Adapter, IP, Hostname). Hint: Sie können natürlich auch eine neue VM mit einem weiteren Betriebssystem aufbauen. Die neue Umgebung hat ja einen anderen Anspruch an Stabilität als die Cluster-Member.

Da der Aufbau der Appliance auch den Zweck des Wissensaufbaus hat, habe ich als Betriebssystem für die analyticsDevelopment VM Fedora gewählt.

Folgende Schritte zur Verteilung (und Konfiguration) der Software sind nun notwendig:

  • Für eine sichere Kommunikation: Einrichtung und Verteilung eines SSH Schlüssels
  • Für die spätere Installations- und Konfigurationsunterstützung: Installation von Ansible in der analyticsDevelopment VM
  • Für die Verteilung der Software: Installation von rsync auf allen VMs
  • Für die Bereitstellung der Runtime für die Hadoop-Komponenten: Herunterladen, verteilen und konfigurieren von JAVA
  • Zur Überwachung der Umgebungen: Installation des Zabbix Agents auf allen VMs
  • Für die Bereitstellung der eigentlichen Hadoop-Komponenten: Herunterladen, verteilen und konfigurieren von Hadoop (HDFS), HBase, Kafka, …
a) Kommunikation via SSH

Zur generellen Konfiguration im Cluster-Member, aber auch zur Ausführung von Ansible Skripten und Playbooks (siehe nachfolgende Beschreibungen), nutzen wir das Netzwerkprotokoll SSH (Secure Shell). Per SSH ist es möglich, sich direkt von seiner lokalen auf die Remote Maschine zu verbinden. Auch unterstützt SSH das Übertragen von Daten per SCP (Secure Copy), so dass wir auch in der Lage sind, Daten von A (lokal) nach B (remote) oder anders herum zu übertragen.

Um SSH nutzen zu können, benötigen wir einen SSH Client und einen SSH Server. Bei den bisher ausgewählten virtuellen Betriebssystemens der Appliance sind diese Voraussetzungen bereits gegeben.

Somit haben wir den:

  • ssh Client und Server auf dem analyticsDevelopment (Fedora)
  • ssh Server auf den anderen Systemen, wie analyticsMaster (centOS)

Zur Überprüfung melden wir uns direkt an den virtuelen Maschinen an: Nach dem Start der VM via Virtualbox Überfläche können wir unseren Benutzernamen und das Passwort eintragen und befinden uns somit direkt in der entsprechenden Umgebung. Starten wir mit analyticsDevelopment.

Mit folgender Eingabe prüfen wir die Verfügbarkeit der SSH Client Binaries:

which ssh
> Ergebnis: /usr/bin/ssh


Hier prüfen wir, ob der SSH Server vorhanden (1) und geladen ist:

systemctl | grep sshd.service
> Ergebnis: sshd.service -> loaded active running -> OpenSSH server daemon


Sollte der Service vorhanden, aber nicht geladen sein, so würden wir als Ergebnis erhalten:

> Ergebnis: sshd.service -> loaded inactive (dead) -> OpenSSH server daemon


In diesem Fall können wir den Service wie folgt starten:

sudo systemctl start sshd.service


Eine umfangreichere Information zum Service erhalten wir durch:

sudo systemctl start sshd.service


Sollte der Service nicht installiert sein, so können wir diesen in einer aktuellen Fedora-Umgebung nachinstallieren:

sudo dnf install openssh-server


Hinweis: Mit Fedora 22 (Auslieferung im Mai 2015) wurde der neue Package Manager DNF (Dandified) für rpm-basierte Linux-Distributionen eingeführt. In centOS 7 wird weiterhin YUM (Yellowdog Updater, Modified) genutzt, da zur Zeit der Bereitstellung der Distribution (im Juli 2014) DNF in Fedora (damals noch Fedora 20 vom Dezember 2013) noch nicht verfügbar war.

Damit wir bei der späteren Verwendung, also der Anmeldung per SSH, an einem unseren Cluster-Member, nicht immer wieder nach einem Passwort gefragt werden, erzeugen wir einen SSH Schlüssel und übertragen diesen auf die einzelnen Umgebungen.

Zuerst erzeugen wir einen Schlüssel mit der RSA-Methode und einer Länge (vielleicht etwas übertrieben) 4096 und übertragen diesen anschliessend von unserer aktuellen Umgebung auf einen Cluster-Member (hier: analyticsMaster):

ssh-keygen -t rsa -b 4096

ssh-copy-id username@analyticsMaster


Hinweis: Bitte ersetzen Sie username durch den Namen, den Sie bei der Installation der virtuellen Umgebungen verwendet haben.

Nach der Übertragung des Schlüssels können wir uns nun ohne Eingabe des Passwortes auf dem Remote-System per SSH anmelden:

ssh username@analyticsMaster


Danach sieht es dann so aus, als ob wir uns direkt auf der Umgebung befinden würden.

b) Installation von Ansible

Da wir in einem Cluster (oder sogar in einem Data Center) eine recht große Anzahl von Maschinen zu verwalten haben, ist es natürlich ratsam, diese nicht manuell zu verwalten bzw. zu konfigurieren. Zu diesem Zweck verwenden wir ansible.

ansible hat den Vorteil, dass es nur auf einer Maschine installiert werden muss und nur eine SSH Verbindung zu den zu verwaltenden Maschinen benötigt.

ansible verwenden wir auf analyticsDevelopment und können es wie folgt installieren:

sudo dnf install ansible


Von nun an können wir ansible durch den einfachen Aufruf des gleichgenannten Binaries verwenden und Systeme über die (bash-)Console verwalten:

ansible --help


ansible kennt allerdings auch sogenannte Strategiebücher (playbooks), um vollständige Abläufe zu automatisieren, wie beispielsweise:

  • Installation von Service A
  • Konfiguration der Umgebung
  • Freigabe der Ports in der Firewall
  • Starten des Services

Wie wir ansible konfigurieren und verwenden, sehen wir im nachfolgenden Punkt. Um die Arbeit mit den Playbooks allerdings ein wenig zu vereinfachen, legen wir zu Beginn einen Alias für den Aufruf des ansible-playbook-Binaries an:

alias ap='/usr/bin/ansible-playbook'



c) Installation von rsync

Für die Verteilung unserer Hadoop-Software-Komponenten könnten wir auch ansible verwenden, da dieses auch die Übertragung von Dateien von A nach B durch ein entsprechendes Modul erlaubt. Ich habe mir allerdings angewöhnt einige zentrale Funktionen zur Reduzierung der Komplexität zu trennen und nutze somit zur Übertragung von Daten (Synchronisation von Verzeichnisstrukturen) rsync.

Damit wir rsync allerdings verwenden können, muss es auf allen Maschinen installiert sein. Und genau das wollen wir nun exemplarisch mit ansible durchführen.

Hinweis: Wir werden später sehen, dass wir durch die Trennung der Funktionen (Synchronisation und Konfiguration) mittels rsync und ansible einen gewissen Mehraufwand haben. Wenn Ihnen das nicht zusagt, sollten Sie sich das zuvor genannte rsync-Modul von ansible im Nachgang mal anschauen.

Zur einfachen Verwendung von ansible setzt diese Komponente auf zwei Konfigurationsdateien:

  • hosts-Datei zur Verwaltung der Maschinen (Inventory)
  • yml-Dateien zur Definition der Strategiebücher (Playbooks)

Die hosts-Datei finden wir in folgendem Ordner:

/etc/ansible


Da es sich um einen System-Ordner handelt, können wir den Inhalt nur wie folgt verändern:

sudo vi /etc/ansible/hosts

.

[analytics:children]
analyticsDevelopmentGroup
analyticsMasterGroup
analyticsWorkerGroup
analyticsBrokerGroup
analyticsDataflowGroup

[analyticsDevelopmentGroup]
analyticsDevelopment

[analyticsMasterGroup]
analyticsMaster

[analyticsWorkerGroup]
analyticsWorker1
analyticsWorker2
analyticsWorker3

[analyticsBrokerGroup]
analyticsBroker1 anyVar=100

[analyticsDataflowGroup]
analyticsDataflow1


Was sehen wir hier? Erst einmal folgt der Aufbau der hosts-Datei einer INI-Datei, in welcher die Sektionen, wie beispielsweise analyticsDevelopmentGroup, über eckige Klammern definiert werden. In den Sektionen finden wir dann die relevanten Einträge (also die Namen der virtuellen Maschinen, die wir zuvor konfiguriert hatten (siehe oben)), die allerdings auch auf andere Sektoren verweisen können (Hierarchie), wie bei analytics:children.

Jeder (!) Eintrag der ansible-hosts-Datei kann später in den Playbooks referenziert werden. Einen besonderen Eintrag finden wir bei analyticsBroker1 und zwar anyVar=100. Auch diesen Eintrag, hier eine zu einer Maschine definierten Variablen (auf die wir hier aber nicht weiter eingehen werden) können wir verwenden, natürich nicht als Host-Referenz, aber als variablen Wert des speziellen Hosts.

Kommen wir nun zu den ansible-playbooks: Um die zugehörigen Dateien einfacher zu handhaben, legen wir in unserem home-Ordner (Hint: wir sind weiterhin in der VM analyticsDevelopment) nun einen entsprechenden Ordner an:

cd; mkdir Ansible


Die Playbooks sind in der YAML Syntax ausgedrückt und unser spezielles Playbook (hier: analytics-yum-install-rsync.yml) zur Installation von rsync auf allen (!) Cluster-Membern sieht wie folgt aus:

vi ~/Ansible/analytics-yum-install-rsync.yml

\

- hosts: analytics
  become: yes
  tasks:
  - name: install rsync
    yum:
      name: rsync
      state: latest


Die erste Zeile (hosts:) definiert die Inventur-Teilnehmer, bei denen die nachfolgenden Tätigkeiten (tasks) ausgeführt werden sollen. Wie zuvor erwähnt können wir alle Einträge der ansible-hosts verwenden. Wir könnten somit rsync anstatt auf allen Umgebungen nur auf einzelnen (z.B. analyticsWorker2) oder einzelnen Gruppen (z.B analyticsMasterGroup) oder auf eine Liste von Umgebungen (z.B. analyticsWorker1, analyticsWorker2, analyticsWorker3, analyticsMasterGroup) installieren. Zur Installation der Software verwenden wir wiederum ein ansible-Modul (hier: yum), welches den Namen (name:) der Software und die Version (state:) erwartet.

Da wir zuvor einen Alias für die Ausführung der ansible-playbooks angelegt hatten, können wir nun das erste Playbook zur Installation von rsync ausführen:

ap ~/Ansible/analytics-yum-install-rsync.yml


Folgende Informationen erhalten wir während der Ausführung:

PLAY [analytics] *******************

TASK [Gathering Facts] *************
ok: [analyticsWorker1]
ok: [analyticsMaster]
ok: [analyticsDevelopment]
ok: [analyticsWorker3]
ok: [analyticsBroker1]
ok: [analyticsWorker2]
ok: [analyticsDataflow1]

TASK [install rsync] ***************
ok: [analyticsDevelopment]
ok: [analyticsMaster]
ok: [analyticsWorker1]
ok: [analyticsWorker2]
ok: [analyticsDataflow1]
ok: [analyticsWorker3]
ok: [analyticsBroker1]

PLAY RECAP *************************
analyticsBroker1           : ok=2    changed=1    unreachable=0    failed=0
analyticsDataflow1         : ok=2    changed=1    unreachable=0    failed=0
analyticsDevelopment       : ok=2    changed=1    unreachable=0    failed=0
analyticsMaster            : ok=2    changed=1    unreachable=0    failed=0
analyticsWorker1           : ok=2    changed=1    unreachable=0    failed=0
analyticsWorker2           : ok=2    changed=1    unreachable=0    failed=0
analyticsWorker3           : ok=2    changed=1    unreachable=0    failed=0


Die Ausgabe startet mit der Angabe der Inventur-Teilnehmer (analytics) und der Einreichbarkeit dieser (Gathering Facts). Sollte ein Teilnehmer nicht erreichbar sein, so würde dieses in diesem Bereich aufgeführt und farblich von dem erreichten Teilnehmer (eigentlich in grün dargestellt) gekennzeichnet. Darauf folgt die Auslistung der im playbook definierten Tasks, hier install rsync. Die Teilnehmer, für die die Software installiert wurde, sind gelb gekennzeichnet.

Die Summe der in den Tasks gelb gekennzeichneten Ausführungen (im Blog leider nicht erkennbar) werden in PLAY RECAP unter changed aufsummiert. Da wir hier nur einen Tasks ausgeführt und, innerhalb dessen, keine Fehler erzeugt haben, sind alle Teilnehmer mit changed=1 gekennzeichnet.

Gerne können Sie sich nun an den einzelnen Maschinen anmelden und prüfen, ob Sie dort rsync vorfinden.

rsync --version



d) Installation von JAVA

Da wir uns zuvor mit den Playbooks von ansible vertraut gemacht haben, geht von nun an alles ganz schnell und einfach.

Denn die Installation folgt nun einem einfacher Muster: Entweder wir übertragen Komponenten per rsync und konfigurieren diese im Anschluss mit ansible oder wir installieren und konfigurieren die notwendige Komponente direkt mit ansible.

Für JAVA nutzen wir nun das erste Vorgehen und müssen zu Beginn die gewünschte JAVA Version von der Webseite von Oracle herunterladen. Da wir (erst einmal) keinen JAVA-Code entwickeln wollen, würde uns sogar die Server JRE reichen.

Hinweis: wir befinden uns nach wie vor auf dem analyticsDevelopment.

Damit wir eine allgemein gültige und gut nachvollziehbare Ordnerstruktur haben, legen wir unsere nun folgenden Ordner unter /opt an. Und damit wir das nicht auf alle Maschinen immer und immer wieder tun müssen, nutzen wir hier natürlich ein ansible-playbook, das wie folgt aussieht und das wir nun nach und nach erweitern:

- hosts: analytics
  tasks:
  - name: create oracle folder javap
    become: true
    file:
      path: /opt/oracle-java
      state: directory
      owner: username
      group: usergroup
      mode: 0775


Bitte ersetzen Sie username und usergroup durch die für Sie passenden Werte.

Nach dem Download des Packets entpacken wir dieses nun unter /opt/oracle-java:

tar xzf server-jre-8u152-linux-x64.tar.gz --directory /opt/oracle-java


Da Oracle seine Dateien in Ordnerstrukturen vorhält, die den Versionsnummern der JRE folgen, erhalten wir nach dem entpacken in /opt/oracle-java einen Unterordner mit der Bezeichnung: jdk1.8.0_152

Um nicht immer wieder die Skripte anpassen zu müssen, falls wir eine neue JAVA-Version verwenden, legen wir einen symbolischen Link zu diesem Ordner mit dem Namen jdk8 an und verweisen fortan auf diesen Link:

ln -s /opt/oracle-java/jdk1.8.0_152 /opt/oracle-java/jdk8


Zur Verteilung der JRE nutzen wir nun rsync und können mit nachfolgendem bash-Skript, welches wir in /opt/oracle-java als rsyncAnalytics.sh speichern, die erste Komponente auf die Umgebungen verteilen:

currentdir=`pwd`
rsync -avxP --delete-after $currentdir/ username@analyticsMaster:$currentdir/
rsync -avxP --delete-after $currentdir/ username@analyticsWorker1:$currentdir/
rsync -avxP --delete-after $currentdir/ username@analyticsWorker2:$currentdir/
rsync -avxP --delete-after $currentdir/ username@analyticsWorker3:$currentdir/
rsync -avxP --delete-after $currentdir/ username@analyticsBroker1:$currentdir/
rsync -avxP --delete-after $currentdir/ username@analyticsDataflow1:$currentdir/


Was passiert hier? Wir synchrosieren und validieren die Synchronisation (Parameter v) den aktuellen Ordner (currentdir=`pwd`) mit dem Remote-Ordner im archiv-Modus (Parameter a) und stellen sicher, dass die File-Systeme der beiden Umgebungen kompatibel sind (Parameter x). Nach der Übertragung werden im Ziel alle Dateien gelöscht, die nicht in der Quelle sind (Parameter –delete-after), so dass wir im Ziel immer eine saubere “Installation” haben.

Achtung: Das bedeutet natürlich im Umkehrschluss, dass wir somit auch alle Daten löschen würden, die sich im Ziel-Ordner befinden. Daher müssen wir bei der Konfiguration immer darauf achten, dass ausführbare Dateien und Daten immer getrennt gespeichert werden. Das klingt selbstverständlich, ist es aber leider nicht immer.

Um JAVA nun auf den Umgebungen nutzen zu können, müssen wir es dort nur noch bekannt geben. Und das geht wieder einfach und per ansible (analytics-set-java.yml):

- hosts: analytics
  tasks:
  - name: check/insert JAVA_HOME
    blockinfile:
      dest: "{{ ansible_env.HOME }}/.bashrc"
      marker: "# {mark} ANSIBLE MANAGED BLOCK -- JAVA"
      block: |
        export JAVA_HOME=/opt/oracle-java/jdk8
        export PATH=$PATH:$JAVA_HOME/bin        
      create: yes
  - name: update-alternative install java
    become: true
    alternatives:
      name: java
      link: /usr/bin/java
      path: /opt/oracle-java/jdk8/bin/java


Wenn Sie mögen, können Sie auch für javac und javaws diese Alternativen nach demselben Schema setzen.

Zur Kontrolle, ob alles geklappt hat, melden wir uns kurz an einer der virtuellen Umgebungen an und prüfen die Verfügbarkeit und Version von JAVA:

ssh username@@analyticsWorker3

java --version



e) Monitoring mit Zabbix

Zur Installation von Zabbix nutzen wir wie schon zuvor das yum-Modul von ansible. Hierbei fügen wir zu Beginn das entsprechende Repository von Zabbix ein und führen dann die Installation aus (analytics-yum-install-zabbix-repo-agent.yml):

- hosts: analytics
  become: yes
  tasks:
  - name: install the zabbix 3.2 rpm from a remote repo
    yum:
      name: http://repo.zabbix.com/zabbix/3.2/rhel/7/x86_64/zabbix-release-3.2-1.el7.noarch.rpm
      state: present

  - name: install zabbix-agent
    yum:
      name: zabbix-agent
      state: latest


Hinweis: Da mein Zabbix-Server noch auf Version 3.2 beruht, nutzen ich hier auch das Repository von 3.2 für den Agent. Bitte passen Sie diese Version Ihren Anforderungen nach an.

Der Agent muss nicht sonderlich aufwendig konfiguriert werden. Er benötigt nur drei Angaben zur Kommunikation mit dem Zabbix-Server.

- hosts: analytics
  tasks:
  - name: Find and replace values from names in zabbix_agentd.conf
    become: true
    lineinfile:
      create: no
      dest: /etc/zabbix/zabbix_agentd.conf
      regexp: "^{{ item.name }}"
      line: "{{ item.name }}{{ item.value }}"
      backrefs: yes # (uncommented because of 'create: no')
      state: present
    with_items:
      - { name: 'Server=', value: '192.168.n.m' }
      - { name: 'ServerActive=', value: '192.168.n.m' }
      - { name: 'Hostname=', value: 'HostNameZabbixServer' }

  - name: enable zabbit-agent service
    become: true
    service:
      name: zabbix-agent
      state: started


Um jedoch nicht mehrfach denselben Task in das Skript aufzunehmen, besteht in ansible die Möglichkeit, über eine Liste von Einträge zu iterieren. Genau das passiert hier mit with_items.

Der darüber stehende Task wird dreimal ausgeführt und ergänzt in der Konfigurationsdatei /etc/zabbix/zabbix_agentd.conf den Eintrag Server, ServerActive und Hostname mit den mit value vorgegeben Werten, die Sie natürlich Ihrer Umgebung nach entsprechend anpassen müssen.

Nachdem der Tasks erolgreich durchgelaufen ist, wird der Agent mit einem zweiten Task (mit dem service-Modul) gestartet.

f) Installation der Hadoop-Komponenten

Da wir uns erst in einem späteren Tutorial um die Daten und Datenstrukturen kümmern, können wir hier und jetzt noch nicht entscheiden, welche Komponenten aus dem Hadoop-Öko-System die für unsere Anforderungen Richtigen sind.

Wo wir uns aber sicher sind, ist, dass wir ein HDFS, Hadoop Distributed File System, benötigen werden. Also starten wir damit.

Das vorgehen ist dem der Installation von JAVA sehr ähnlich:

Konkret sieht das dann wie folgt aus:

wget http://ftp.halifax.rwth-aachen.de/apache/hadoop/common/hadoop-2.8.2/hadoop-2.8.2.tar.gz

.

# Dateiname: analytics-create-apache-opt.yml
- hosts: analytics
  tasks:
  - name: create apache folder hadoop
    become: true
    file:
      path: /opt/apache-hadoop
      state: directory
      owner: username
      group: usergroup
      mode: 0775

.

ap analytics-create-apache-opt.yml

tar xzf hadoop-2.8.2.tar.gz --directory /opt/apache-hadoop

ln -s /opt/apache-hadoop/hadoop-2.8.2 /opt/apache-hadoop/hadoop


(hier passiert ein kleines Wunder; Erläuterung etwas weiter unten)

# Dateiname: rsyncAnalytics.sh
currentdir=`pwd`
rsync -avxP --delete-after $currentdir/ username@analyticsMaster:$currentdir/
rsync -avxP --delete-after $currentdir/ username@analyticsWorker1:$currentdir/
rsync -avxP --delete-after $currentdir/ username@analyticsWorker2:$currentdir/
rsync -avxP --delete-after $currentdir/ username@analyticsWorker3:$currentdir/
rsync -avxP --delete-after $currentdir/ username@analyticsDataflow1:$currentdir/

ssh username@analyticsWorker1 rm $currentdir/hadoop/etc/hadoop/slaves
ssh username@analyticsWorker2 rm $currentdir/hadoop/etc/hadoop/slaves
ssh username@analyticsWorker3 rm $currentdir/hadoop/etc/hadoop/slaves
ssh username@analyticsDataflow1 rm $currentdir/hadoop/etc/hadoop/slaves

.

sh /opt/apache-hadoop/rsyncAnalytics.sh

.

# Dateiname: analytics-set-hadoop.yml
- hosts: analytics
  tasks:
  - name: check/insert HADOOP_HOME
    blockinfile:
      dest: "{{ ansible_env.HOME }}/.bashrc"
      marker: "# {mark} ANSIBLE MANAGED BLOCK -- HADOOP"
      block: |
        export HADOOP_HOME=/opt/apache-hadoop/hadoop
        export HADOOP_COMMON_HOME=$HADOOP_HOME
        export HADOOP_HDFS_HOME=$HADOOP_HOME
        export PATH=$PATH:$HADOOP_HOME/bin        
      create: yes

- hosts: analyticsMasterGroup
  tasks:
  - name: create apache folder haddop namenode
    become: true
    file:
      path: /analyticsData/data/hadoop/hdfs/namenode
      state: directory
      owner: username
      group: usergroup
      mode: 0750

- hosts: analyticsWorkerGroup
  tasks:
  - name: create apache folder haddop datanode
    become: true
    file:
      path: /analyticsData/data/hadoop/hdfs/datanode
      state: directory
      owner: username
      group: usergroup
      mode: 0750

.

ap analytics-set-hadoop.yml



Ein kleines Wunder

Nach der Anlage des symbolischen Links ist ein kleines Wunder passiert. Und zwar das Wunder der Konfiguration des HDFS-Clusters. Dieser Blog dient uns zum Verständnis des Aufbaus einer Data Analytics Plattform. Keine Sorge, ich bleibe Ihnen die Konfiguration von HDFS nicht schuldig. Ich wollte nur diese ohnehin schon sehr umfangreich Seite nicht mit noch umfangreicheren ansible-playbook-Skripten oder HDFS-Konfigurationsdateien füllen. Daher finden Sie hier die notwendigen Konfigurationsdateien unseres HDFS-Clusters.

Der letzte Schritt zum Bereitstellen des Hadoop Distributed File Systems ist die Formatierung dessen. Das klingt beängstigend. Aber machen Sie sich keine Sorge, denn erstens haben wir oben schon etwas vorgesorgt und zweitens ist der Vorgang jederzeit reproduzierbar.

Warum haben wir vorgesorgt? Nun, in dem Strategiebuch analytics-set-hadoop.yml haben wir für den analyticsMaster und für die einzelnen Worker (analyticsWorker1, analyticsWorker2, analyticsWorker3) einen besonderen Ordner (namenode bzw. datanode) angelegt. Wie Sie sehen befinden sich beide Ordner ausserhalb der ausführbaren Apache Hadoop Dateien (/opt/apache-hadoop).

In diesen beiden Ordner befindet sich nach der Formatierung sozusagen das HDFS, denn an sich wird dieses nur über eine gewisse Anzahl von Dateien repräsentiert, die von Namenode des HDFS-Master verwaltet werden.

Sollten wir somit nach der Formatierung des HDFS feststellen, dass uns das gar nicht gefällt, was wir gemacht haben, so löschen wir einfach die Inhalte der beiden Ordner und starten neu. That’s it.

Zur Bereitstellung des HDFS verbinden wir uns nun mit dem analyticsMaster und formatieren den HDFS-Cluster:

ssh username@analyticsMaster

hdfs namenode -format


Zum Schluss müssen wir “nur noch” den HDFS-Cluster starten und können uns dann mit der WebUI, welches standardmäßig über Port 50070 erreichbar ist, verbinden:

/opt/apache-hadoop/hadoop/sbin/start-dfs.sh