Wie wird ein Hochverfügbarkeits-MQTT-Cluster für das Internet der Dinge aufgebaut ?

vPierre Automation, Cloud, IoT (Internet of Things), Linux, Scripts, WWW Leave a Comment

Aufbau einer skalierbaren MQTT-Infrastruktur mittels Node.js, Redis, HAProxy und nscale, um die Installation zur leichten Übung zu machen

1.TL;DR

In diesem Artikel zeige ich, wie ein skalierbarer MQTT-Cluster für das Internet der Dinge aufgebaut wird. Alles stammt von den Arbeiten von Lelylan. Falls das für Dich und Deine Arbeit nützlich ist, gib dem Projekt einen Stern auf Github. Das unterstützt die Entwickler.

Lelylan
Eine offene und schlanke Mikroservices-Architektur für das Internet der Dinge. Für Entwickler. github.com

2.Worüber sprechen wir?

In einer professionellen Umgebung des Internets der Dinge sind Verfügbarkeit und Skalierbarkeit ihrer Dienste ein entscheidender Faktor, auf den zu achten gilt. Für MQTT-Umgebungen bedeutet das, dein Broker braucht eine stabile Verbindung, unterbrechungsfreie Funktionalität und die Möglichkeit zur Aktualisierung Deiner privaten Cloud-Infrastruktur, während diese aktiv läuft. In diesem Artikel zeigen wir Schritt für Schritt alles, was wir bei Aufbau einer derartigen Umgebung für Lelylan gelernt haben.

Geräte verbinden sich mit einem Loadbalancer und leiten alle Verbindung an zwei MQTT-Server weiter.

Hauptvorteil einer solchen Infrastruktur ist, dass auch beim Ausfall eines MQTT-Servers die noch vorhandenen Broker den Verkehr übernehmen können. Mit anderen Worten, falls einer der zwei (oder mehr) Knoten ausfällt, leitet der Loadbalancer sämtlichen eingehenden Verkehr zum funktionierenden Cluster-Knoten um, und es gibt keine Unterbrechungen auf der Client-Seite.

Wir wollten auch den Installationsprozess vereinfachen. Mittels nscale war das gewünschte Ergebnis leicht zu erreichen, wo wir auf 2 (oder mehr) MQTT-Servern installieren können und dazu nur folgende zwei Befehle benötigen:

$ nsd cont buildall
$ nsd rev dep head

3.Gib mir ein paar Tools

Nachfolgend die Liste der verwendeten Tools, um zum Ziel zu kommen.

Mosca. A Node.js MQTT-Server/Broker. Er ist kompatibel zu MQTT 3.1 und unterstützt QoS 0 sowie QoS 1 zusammen mit den Speicheroptionen für Offline-Pakete und Abonnements.

HAProxy. Eine kostenlose, schnelle und zuverlässige Lösung für Hochverfügbarkeit, Loadbalancing und Proxy-Bereitstellung für TCP- und HTTP-basierte Anwendungen. Sie eignet sich für Webseiten mit sehr hohem Datenverkehr.

Docker. Docker ist eine offene Plattform für Entwickler und Systemadmins für Aufbau, Bereitstellung und Betrieb verteilter Anwendungen, so dass Anwendungen schnell aus Komponenten zusammengestellt werden können und Konflikte zwischen Entwicklungs- und Produktiv-Umgebungen beseitigt werden.

Nscale. Ein offenes Opensource-Projekt zur einfachen Konfiguration, Konstruktion und Installation einer Reihe von verbundenen Containern, um eine Arbeitsplattform für verteilte Anwendungen zu schaffen (mittels nscale kannst du leicht einen Prozess zur Installation von Systemen basierend auf Mikroservices formalisieren).

Redis. Ein Opensource und BSD-lizensierter moderner Key-Value Cache und Speicher.

4.So, wo fangen wir an?

Diesen Schritten folgen wir, um Schritt für Schritt ein Hochverfügbarkeits-MQTT-Cluster für das Internet der Dinge aufzubauen.

  1. Einrichtung des MQTT-Servers.

  2. Dockerisierung unseres MQTT-Servers.

  3. Einbau von HAProxy als Loadbalancer.

  4. Absicherung von MQTT mit SSL.

  5. Konfiguration von nscale zur Automatisierung der Installationsabläufe.

  6. Abschließende Betrachtungen

5.Einrichtung des MQTT-Brokers

MQTT ist ein Verbindungsprotokoll für Machine-to-Machine (M2M)/“Internet der Dinge”. Es wurde als extrem schlankes Publish/Subscribe-Kommunikationsprotokoll entwickelt und ist für Verbindungen mit Remote-Standorten nützlich, wenn eine geringe Code-Größe gefordert ist und Netzwerkbandbreite Vorrang hat.

 

Vor zwei Jahren suchten wir erstmalig eine MQTT-Lösung. Wir suchten eine sichere (auf Authentisierung basierte), anpassbare (Kommunikation mit unserer REST API) und einfache nutzbare Lösung (wir kannten Node.js). In Mosca fanden wir die richtige Lösung und sind nach zwei Jahren glücklich mit unserer Wahl

Die Hauptargumente für die Wahl unseres MQTT-Servers können sich von Deinen unterscheiden. In dem Fall prüfe diese Liste der MQTT-Server und ihrer Fähigkeiten.

Gib mir ein Code-Beispiel

Wir werden nicht jede Codezeile beschreiben, sondern anhand von zwei Hauptabschnitten zeigen, wie einfach die Einrichtung eines MQTT-Servers sein kann.

Der von uns verwendete Code zum Betrieb des MQTT-Servers auf Lelylan ist verfügbar auf Github.

Einrichtung des MQTT-Servers

Der nachstehende Code dient zum Start des MQTT-Servers. Zuerst konfigurieren wir die pub/sub-Einstellungen mittels Redis, dann übergeben wir das pub/sub-Einstellungsobjekt an unseren Server und sind fertig.

Nötiger Node.js-Code zum Betrieb eines einfachen MQTT-Servers

Wenn Du dich fragst, warum Redis als pub/sub-Lösung nötig ist, lese die Frage Q1 in der FAQ. Kurzgesagt brauchen wir das, um den Kommunikationskanal zwischen dem MQTT-Server und anderen Mikroservices von Lelylan zu öffnen.

Authentisierung der physischen Objekte

Mit Mosca kannst du einen Client mittels drei Methoden autorisieren, wobei jede davon die erreichbaren Themen für einen bestimmten Client beschränkt.

#authenticate
#authorizePublish
#authorizeSubscribe

In Lelylan verwenden wir die authenticate method zur Überprüfung von Benutzername und Kennwort des Clients. Wenn die Authentisierung erfolgreich ist, wird die device_id im Client-Objekt gespeichert, und später zur Autorisierung (oder nicht) der Funktionalitäten Publish und Subscribe verwendet.

Wenn Du mehr über MQTT und Lelylan erfahren möchtest, schaue im Entwicklerzentrum nach.

6.Dockerisierung unseres MQTT-Servers

Docker ist ein tolles Tool zum Aufspielen produktiver Systeme. Du kannst dabei den Code in einer sauberen Systemumgebung isolieren, indem Du eine Docker-Datei, definierst, ein zur Initialisierung einer Systemumgebung verwendetes “Rezept”. 

Docker. Ein tolles Tool zum Aufspielen produktiver Systeme

Cool! Fangen wir an.

Container-Definition

Zum Aufbau eines Containers um unsere Anwendung müssen wir zuerst eine Datei namens Docker-Datei anlegen. Darin packen wir alle nötigen Befehle für Docker, um die gewünschte Umgebung zu initialisieren.

In der Docker-Datei für den Container rund um den MQTT-Server fragen wir nach einer bestimmten Version von Node.js (FROM node:0.10-onbuild), fügen alle Dateien des Repository hinzu (ADD ./ .), installieren die Knoten-Pakete (RUN npm install), öffnen den Port 1883 (EXPOSE 1883) und führen schließlich die Knoten-App aus (ENTRYPOINT [“node”, “app.js”]). Das ist schon alles.

Docker-Image ausführen

Sobald wir eine Docker-Datei haben, können wir einen Docker-Container bauen (falls Docker noch nicht installiert ist, mache es einfach – das unterstützt alle gängigen Plattformen, sogar Windows ). Wenn Docker installiert ist, können wir den Container bauen.

# building a container
$ docker build -t lelylan/mqtt

Das führt letztendlich zur Ausgabe

Successfully built lelylan/mqtt

Nachdem wir den Container gebaut haben, können wir ihn starten und ein Arbeits-Image erhalten.

docker run -p 1883:1883 -d lelylan/mqtt

Und wir sind fertig! Jetzt können wir Anfragen an unseren MQTT-Server senden.

Beim Einstieg zu Docker können Container und Images leicht verwechselt werden. Lese nach, was beide von ihnen bedeuten, um das besser zu verstehen.

# OSX
$ http://$(boot2docker ip):1883

# Linux
$
http://localhost:1883

Wenn Du OS X verwendest, verwenden wir dockertoolbox, was in der Tat eine Linux VM ist. Wir müssen die Umgebungsvariable $DOCKER_HOST verwenden, um auf den localhost der VM zuzugreifen. Wenn Du andererseits Linux nutzt, verwende localhost.

Weitere Befehle, die wir oft verwenden

Beim Erlernen des Umgangs mit Docker haben wir eine Liste gängiger Befehle aufgeschrieben. Sie sind alle einfach, aber sicher eine praktische Referenz zum Nachschauen.

Container-bezogene Befehle

# einen Container ohne Tag bauen und ausführen
$ docker build .
$ docker run -p 80:1883 <CONTAINER_ID>

# Container mit einem Tag bauen und ausführen
$ docker build -t <USERNAME>/<PROJECT_NAME>:<V1>
$ docker run -p 80:1883 -d <USERNAME>/<PROJECT_NAME>:<V1>

Image-bezogene Befehle

# interaktiv in einem Image ausführen
$ docker run -i <IMAGE_ID> /bin/bash

# Image mit Umgebungsvariablen ausführen (an den Anfang stellen)
$ docker run -e „VAR=VAL“ -p 80:1883 <IMAGE_ID>

# alle laufenden Images anzeigen
$ docker ps

# alle laufenden und nicht laufenden Images anzeigen
# (nützlich, um auch Images zu sehen, die wegen eines Fehlers beendet wurden).
$ docker ps -a

Images killen

# alle Images killen
docker ps -a -q | xargs docker rm -f

Log-bezogene Befehle

# Logs für ein bestimmtes Image anzeigen
docker logs <IMAGE_ID>

# Logs mit tail mode anzeigen
docker logs -f <IMAGE_ID>

7.HAProxy als Loadbalancer hinzufügen

An dieser Stelle haben wir eine dockerisierten MQTT-Server, der Verbindungen von jedem physischen Objekt (Client) annehmen kann. Es fehlt noch die Skalierung, bisher .

Hier kommt HAProxy ins Spiel, ein beliebter TCP/HTTP-Loadbalancer und Proxy-Lösung für verbesserte Leistung und Zuverlässigkeit einer Server-Umgebung, der die Arbeitslast auf mehrere Server verteilt. Er ist in C geschrieben und gilt als schnell und effizient.

Terminologie

Bevor wir zeigen, wie wir HAProxy genutzt haben, gibt es einige Konzepte, die man für den Einsatz von Loadbalancing wissen muss.

Neugierige finden vielen nützliche Informationen in diesem Artikel von Mitchell Anicas

Zugriffskontrollliste / Access Control List (ACL)

ACLs dienen zum Testen von Bedingungen und zum Ausführen einer Aktion (z.B. Auswahl eines Servers oder Sperrung einer Anfrage) basierend auf dem Testergebnis. Der Einsatz von ACLs ermöglicht eine flexible Weiterleitung des Netzwerkverkehrs basierend auf verschiedenen Faktoren wie Mustervergleich oder der Anzahl der Verbindungen zum Backend.

# Diese ACL passt, wenn der Pfad der Benutzeranfrage beginnt mit /blog
# (passen würde eine Anfrage von http://example.org/blog/entry-1)
acl url_blog path_beg /blog

Backend

Ein Backend ist eine Gruppe von Servern, die weitergeleitete Anfragen erhält. Allgemein steigt die potenzielle Lastkapazität und Zuverlässigkeit, wenn mehr Server dem Backend hinzugefügt werden und die Last über sie verteilt wird. Folgendes Beispiel zeigt eine Backend-Konfiguration mit zwei Web-Servern, die am Port 80 lauschen.

backend web-backend
balance roundrobin
server web1 web1.example.org:80 check
server web2 web2.example.org:80 check

Frontend

Ein Frontend definiert, wie Anfragen zum Backend weitergeleitet werden. Frontends werden im Abschnitt frontend der HAProxy-Konfiguration definiert, und sie vereinen IP-Adressen, ACLs und Backends. Wenn ein Benutzer im folgenden Beispiel example.com/blog anfragt, wird das weitergeleitet zum blog Backend, was eine Gruppe von Servern ist, auf denen die Blog-Anwendung läuft. Andere Anfragen werden weitergeleitet zum web-backend, wo eine andere Anwendung laufen kann.

frontend http
bind *:80
mode http

acl url_blog path_beg /blog
use_backend blog-backend if url_blog

default_backend web-backend

Schluss mit der Theorie! Konfigurieren wir HAProxy

Der von uns verwendete Code für den Betrieb des HAProxy-Servers auf Lelylan ist festgelegt durch eine Docker-Datei und eine Konfigurationsdatei, die festlegen, wie Anfragen gehandhabt werden.

Der von uns verwendete Code für HAProxy ist abrufbar auf Github

Lade deine HAProxy-Container vom Docker-Hub herunter

Zum Start laden Sie den HAProxy-Container vom öffentlichen Docker-Hub Verzeichnis herunter (eine automatisierte einsatzfertige Version ist enthalten).

$ docker pull dockerfile/haproxy

An dieser Stelle führe den HAProxy-Container aus.

$ docker run -d -p 80:80 dockerfile/haproxy

Der HAProxy-Container akzeptiert eine Konfigurationsdatei als Datenlaufwerk (wie im nachstehenden Beispiel zu sehen ist), wo <override-dir> ein absoluter Pfad eines Ordners ist, der haproxy.cfg enthält (eigene Konfigurationsdatei) und errors/ (eigene Fehlermeldungen).

# HAProxy-Image mit eigener Konfigurationsdatei ausführen
$ docker run -d -p 1883:1883 \
-v <override-dir>:/haproxy-override dockerfile/haproxy

Das eignet sich perfekt zum Test einer Konfigurationsdatei

HAProxy-Konfiguration

Folgt auf die Konfiguration unserer MQTT-Server, wo HAProxy auf alle Anfragen für Port 1883 lauscht und diese zu zwei MQTT-Servern weiterleitet (mosca_1 und mosca_2) und dafür den leastconn Balance-Modus verwendet (wählt den Server mit der geringsten Anzahl von Verbindungen).

2. Für die von Lelylan verwendete Endkonfiguration prüfe haproxy.cfg auf Github. 1. Bei der HAProxy-Einführung haben wir die Konzepte ACL, Backend und Frontend beschrieben. Hier haben wir einen kürzeren, aber weniger Aussagekräftigen Weg verwendet, um all diese Konzepte zusammen zu definieren. Wegen einiger Probleme bei Backend und Frontend haben wir diesen Weg gewählt. Wenn Du eine funktionierende Konfiguration dafür herausfindest, lasse es uns wissen.

Zum Test der neuen Konfiguration (hilfreich bei der Entwicklung), überschreibe die standardmäßigen mit der Option für das Datenlaufwerk. Im folgenden Beispiel überschreiben wir haproxy-override mit der Konfigurationsdatei aus /root/haproxy-override/.

$ docker run -d -p 80:80 1883:1883 \
-v
/root/haproxy-override:/haproxy-override
dockerfile/haproxy

Deinen HAProxy-Docker-Container anlegen

Sobald wir eine funktionierende Konfiguration haben, können wir einen neuen HAProxy-Container einrichten. Dafür müssen wir lediglich eine Docker-Datei definieren, welche den HAProxy-Container lädt (FROM dockerfile/haproxy) wohin wir die Konfigurationsdatei ersetzen, die in /etc/haproxy/haproxy.cfg definiert ist (ADD haproxy.cfg /etc/haproxy/haproxy.cfg). Dann starten wir den HAProxy-Server neu (CMD [“bash”, “/haproxy-start”]) und öffnen die gewünschten Ports (80/443/1883/8883).

HINWEIS. Wir starten HAProxy neu und starten nicht einfach nur, weil beim Laden des anfänglichen HAProxy-Containers HAProxy bereits läuft. Das bedeutet auch, dass wir bei einer Änderung an der Konfigurationsdatei einen frischen Neustart benötigen, um sie zu laden.

Zusatztipps für HAProxy

Bei Problemen mit HAProxy lese die Log-Files! HAProxy verwendet rsyslog, eine sehr schnelles System für Logverarbeitung, das standardmäßig in Ubuntu verwendet wird.

# HAProxy log configuration file
$ vi /etc/rsyslog.d/haproxy.conf

# Files where you can find the HAProxy logs
$ tail -f /var/lib/haproxy/dev/log
$ tail -f /var/log/haproxy.log

8.MQTT mit SSL absichern

Jetzt haben wir eine skalierbare MQTT-Infrastruktur, wo alle Anfragen über HAProxy an zwei (oder mehr) MQTT-Server geleitet werden. Der nächste Schritt ist die Absicherung der Kommunikation mittels SSL.

Die native SSL-Unterstützung wurde in HAProxy 1.5.x eingeführt, das im Juni 2014 als stabile Version veröffentlicht wurde.

Was ist SSL?

SSL (Secure Sockets Layer) ist der etablierte Standard für verschlüsselte Kommunikation zwischen einem Server und einem Client und stellt sicher, dass alle zwischen Server und Client übertragenen Daten vertraulich und integer bleiben.

Eine kombinierte PEM SSL Zertifikat/Schlüssel-Datei anlegen

Zuerst benötigest Du ein SSL-Zertifikat. Zur Realisierung von SSL mit HAProxy müssen SSL-Zertifikat und Schlüsselpaar das richtige Format haben: PEM.

In den meisten Fällen kombinierst Du einfach Dein SSL-Zertifikat (.crt oder .cer Datei von einer Zertifikat-Autorität) und deren entsprechenden privaten Schlüssel (selbst erzeugte .key-Datei). Wenn die Zertifikatdatei beispielsweise lelylan.com.crt heißt und deine private Schlüsseldatei lelylan.com.key heißt, zeigt folgendes Beispiel, wie Du beide Dateien kombinieren kannst, um die PEM-Datei lelylan.com.pem zu erzeugen.

cat lelylan.com.crt lelylan.com.key > lelylan.com.pem

Achte wie stets darauf, Kopien der Datei Deines privaten Schlüssels anzulegen, einschließlich der PEM-Datei (die den privaten Schlüssel enthält).

Laden der PEM-Datei mittels Docker-Laufwerken

Nachdem wir unser SSL-Zertifikat angelegt haben, können wir es nicht öffentlich speichern. Du weißt, Sicherheit . Wir müssen es zum HAProxy-Server bringen und den Zugriff von Docker über Datenlaufwerke ermöglichen.

Was ist ein Docker-Datenlaufwerk?

Ein Datenlaufwerk ist ein speziell zugeordneter Ordner innerhalb einer oder mehrerer Container, der nützliche Funktionen zum Datenaustausch bietet. Einem Container kannst Du ein Datenlaufwerk hinzufügen und dabei das Flag -v verwenden, um alle Dateien/Ordner freizugeben, -v mehrfach verwenden, um mehrere Datenlaufwerke zu mounten (wir haben das bereits genutzt, um eine Konfigurationsdatei für den HAProxy-Container zu laden).

Freigabe eines SSL-Zertifikats mittels Datenlaufwerken.

Zur Freigabe unseres SSL-Zertifikats bringen wir es in /certs (im HAProxy-Server) und ermöglichen den Zugriff über den Ordner /certs beim Betrieb des Docker-Containers.

$ docker run -d -p 80:80 -p 443:443 -p 1883:1883 -p 8883:8883 \
-v /certs:/certs
-v /root/haproxy-override:/haproxy-override

Vergiss nicht, den Port 8883 zu öffnen (der standardmäßig für sichere MQTT-Verbindungen vorgesehen ist)

Laden des SSL-Zertifikats

Wenn wir das SSL-Zertifikat über das Docker-Datenlaufwerk verfügbar haben, können wir von der HAProxy-Konfigurationsdatei darauf zugreifen. Wir müssen nur eine Codezeile hinzufügen, um die am Port 8883 ankommenden Anfragen auf das SSL-Zertifikat zu mappen, das sich in /certs befindet und lelylan.pem heißt.

Wir sind nun fertig!

An dieser Stelle haben wir einen sicheren und hochverfügbaren MQTT-Cluster für das Internet der Dinge. Nachstehendes Bild zeigt das Endergebnis.

 

Geräte mit Verbindung zum Loadbalancer, die alle Verbindungen an zwei MQTT-Server weiterleiten. Bild Copyright HiveMQ.

An dieser Stelle gibt es leider noch etwas zu tun, um die Architektur zu komplettieren: wir brauchen einen einfachen Weg, um sie zu implementieren.

9.Konfiguration von nscale zur Automatisierung des Implementierungsablaufes

Dafür verwenden wir nscale, ein OpenSource-Projekt zum Konfigurieren, Aufbauen und Implementieren mehrerer verbundener Container.

Während wir nur die wichtigsten Befehle von nscale beschreiben, gibt es hier eine Anleitung, welche den Einsatz von nscale Schritt für Schritt erläutert.

Wo implementieren wir das alles?

Digital Ocean ist ein einfaches Cloud-Hosting für Entwickler. Für unsere Implementierungslösung basieren alle verwendeten Droplets auf Ubuntu und haben Docker bereits installiert.

 

Droplet-Definition

Du hast kein Konto bei Digital Ocean? Melde Dich über diesen Link an und erhalte 10$ Gutschrift.

Zuerst mussten wir 5 Droplets anlegen, die jeweils einer speziellen App gewidmet waren: 1 Management-Maschine (wo das Login zu nscale läuft), 1 HAProxy Loadbalancer, 2 MQTT Mosca-Server und 1 Redis-Server. 

Liste der in Digital Ocean für diese Anleitung angelegten Droplets

Liste der in Digital Ocean für diese Anleitung angelegten Droplets.

Installation von nscale

Wir können nscale jetzt auf der Management-Maschine installieren, die auf Digital Ocean definiert ist. Wir hätten auch unsere lokale Maschine verwenden können, aber ein dedizierter Server dafür macht es für alle Team-Mitglieder einfach, neue Änderungen zu implementieren.

Installation

Installieren Sie Node.js via nvm (Node Version Manager).

curl https://raw.githubusercontent.com/creationix/nvm/v0.18.0/install.sh | bash

Melde dich ab und wieder an und führe folgende Befehle aus.

# install needed dependencies
apt-get update
apt-get install build-essential

# install node and npm
nvm install v0.10.33
nvm alias default v0.10.33
npm install
[email protected]

-g –unsafe-perm

# install nscale
npm install nscale -g –unsafe-perm

Die Installation kann eine Weile dauern, das ist normal

Github Benutzer-Konfiguration

Zur Nutzung von nscale musst Du GIT konfigurieren.

git config –global user.name „<YOUR_NAME>“
git config –global user.email „<YOUR_EMAIL>“

Dein erstes Projekt mit nscale anlegen

Wenn die Konfiguration abgeschlossen ist, melde dich bei nscale an.

$ nsd login

An dieser Stelle können wir unser erstes Projekt mit nscale anlegen, wobei Du gefragt wirst, einen Namen und einen Namensraum festzulegen (wir verwendeten jeweils denselben).

$ nsd sys create
1. Set a name for your project: <NAME>
2. Set a namespace for your project: <NAMESPACE>

Dieser Befehl erzeugt einen automatisch generierten Projektordner mit folgender Struktur (keine Sorge bei all den Dateien; die einzigen wichtigen für uns sind definition/services.js und system.js).

|— definitions
| |— machines.js
| `— services.js *
|— deployed.json
|— map.js
|— npm-debug.log
|— README.md
|— sudc-key
|— sudc-key.pub
|— system.js *
|— timeline.json
`— workspace

An dieser Stelle verwendest Du den Befehl list und prüfst, ob das neue Projekt mit nscale läuft. Wenn alles gut ist, siehst Du den Projektnamen und die Id.

$ nsd sys list
Name Id

lelylan-mqtt 6b4b4e3f-f22e-4516-bffb-e1a8daafb3ea

Sicherer Zugriff (von nscale auf andere Server)

Zum Zugriff auf alle Server benötigt nscale einen neuen ssh-Schlüssel für die sichere Authentisierung ohne Passwort.

ssh-keygen -t rsa

Vergebe kein Passwort und speicher das mit Ihrem Projektnamen. In unserem Fall nannten wir das lelyan-key (man beachte, dass der neue ssh-Schlüssel im Stammverzeichnis des nscale-Projekts sein muss, nicht in ~/.ssh/). Wenn der ssh-Schlüssel angelegt ist, richtest Du den öffentlichen Schlüssel in allen Servern ein, die nscale konfigurieren muss: haproxy, mosca 1, mosca 2 und redis.

Das geht über das Dashboard von Digital Ocean oder durch Hinzufügen des öffentlichen Schlüssels für nscale zu den authorized_keys mit folgendem Befehl.

cat lelylan-key.pub | \
ssh <USER>@<IP-SERVER> „cat ~/.ssh/authorized_keys“

Falls Probleme auftreten, verbindest Du dich zuerst über SSH mit dem Server

ssh <USER>@<IP-SERVER>

SSH Agent-Weiterleitung

Was Du noch an Deinem Management-Server (wo des nscale-Projekt definiert ist) machen musst, ist die Einrichtung der SSH Agent-Weiterleitung. Damit kannst Du deine lokalen SSH-Schlüssel verwenden anstatt die Schlüssel auf Deinem Server zu speichern.

# ~/.ssh/config
Host *
ForwardAgent yes

Es gibt ein offenes Problem dafür auf nscale. Wenn Du das nicht einrichtest, funktioniert die Implementierung mit nscale nicht.

Konfiguration von nscale

Jetzt können wir nscale konfigurieren, angefangen vom nscale-Analyzer, der die Autorisierungseinstellungen für den Zugriff auf die Zielmaschinen definiert. Dazu bearbeiten wir ~/.nscale/config/config.json durch Einstellungen des specific Objekts von:

{

„modules“: {

„analysis“: {
„require“: „nscale-local-analyzer“,
„specific“: {
}
}

}

auf:

{

„modules“: {

„analysis“: {
„require“: „nscale-direct-analyzer“,
„specific“: {
„user“: „root“,
„identityFile“: „/root/lelylan/lelylan-key“

}
}
}

Passe dies deinen Bedürfnissen an, wenn Du Projekt und Schlüssel anders benannt hast.

Wir haben lediglich das Objekt specific mit dem user (root) befüllt und dem identity file (ssh-Schlüssel) (dieser Schritt wird in einer nächsten Version vermutlich nicht mehr benötigt).

Prozess-Definition

In nscale können wir verschiedene Prozesse definieren, wobei jeder Prozess ein Docker-Container ist, der durch einen Namen, ein Github-Repo (mit dem Quellcode des Containers) und eine Reihe von Argumenten identifiziert ist, die Docker beim Ausführen des Images verwendet.

Falls Du bemerkt hast, dass Redis kein Github-Repo hat, Glückwunsch! An dieser Stelle des Artikels sollte das nicht einfach sein . Für Redis brauchen wir kein Github-Repo, weil wir das im Docker-Hub definierte Redis-Image direkt verwenden.

In diesem Fall haben wir drei verschiedene Prozessarten: haproxy, mqtt und redis.

System-Definition

Nachdem wir nun die auszuführenden Prozesse definiert haben, können wir nscale sagen, wo jeder davon auf Digital Ocean sein soll, indem wir die system.js Definition verwenden.

Wie Du siehst, definiert system.js die Einrichtung aller Maschinen. Für jede davon definieren wir die laufenden Prozesse (Sie müssen einen zwischen den zuvor in services.js) definierten verwenden, die IP-Adresse der Maschine, der erlaubte Benutzer und der ssh-Schlüssel, um den Zugang zu autorisieren.

Was ist, wenn ich einen neuen MQTT-Server hinzufügen will

Füge der nscale-Definition system.js eine neue Maschine hinzu, den neuen Server zur HAproxy-Konfiguration und Du kannst loslegen.

Zeit zur Implementierung

Jetzt können wir unsere Infrastruktur kompilieren, aufbauen und implementieren.

# nscale-Projekt kompilieren
nsd sys comp direct

# Alle Container bauen
# (nehmen Sie eine Tasse Kaffee, während nscale alles zusammenbaut)
nsd cont buildall

# Aktuelle Version auf Digital Ocean implementieren
nsd rev dep head

Während wir die nötigen Konfigurationen zur Implementierung auf Digital Ocean beschrieben haben, eignet sich nscale auch dazu, alle Dienste lokal auszuführen.

Du bist fertig!

Wenn die Einrichtung mit den letzten drei Befehlen abgeschlossen ist, können wir innerhalb von Minuten einen hochverfügbaren MQTT-Cluster für das Internet der Dinge implementieren, neue MQTT-Server hinzufügen und unsere Infrastruktur skalieren.

10.Schlussfolgerungen

Dieser Artikel basiert auf meinen Arbeiten in Lelylan, einer Open Source Cloud-Plattform für das Internet der Dinge. Wenn Du diesen Artikel hilfreich findest, gib uns einen Stern auf Github (das hilft, mehr Entwickler zu erreichen).

Quellcode

In diesem Artikel haben wir gezeigt, wie ein hochverfügbarer MQTT-Cluster für das Internet der Dinge gebaut wird. Aller von uns produktiv verwendeter Code ist nun als OpenSource veröffentlicht wie folgt.

Bald werden wir auch das nscale-Projekt veröffentlichen (momentan enthält es noch sensible Informationen, die wir aus dem Repo entfernen müssen).

Vielen Dank an nearForm und Matteo Collina (Autor von Mosca und Teil des nscale-Teams) für die Hilfe bei der Beantwortung alle Fragen, die wir zu nscale und der MQTT-Infrastruktur hatten.

Das Aufbauen, Testen und Absichern einer solchen Infrastruktur bedeutete mehrere Monate Arbeit. Wir hoffen, dass die Veröffentlichung als Open Source anderen hilft, MQTT-Plattformen schneller zu bauen.

Willst Du mehr erfahren?

Unzufrieden? Wenn Du mehr zu einigen der angesprochenen Themen erfahren willst, lese die folgenden Artikel!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.