Docker Swarm an einem Beispiel

16 Jun 2019 - Lesezeit: 5 Minuten

Wenn es ein Thema gibt, das in den letzten Jahren fahrt aufgenommen hat, dann ist es wohl das Thema der Containerisierung. Nicht das es neu oder revolitionär wäre. Immerhin habe es einige gute Systeme vorher schon implementiert gehabt. Aber das Tooling drum herum war nur den adeligen gegeben. Dank Docker ist dem nun nicht mehr so. Standalone auf einem Server ein paar Container zu starten ist wirklich kein Hexenwerk. Spaß macht es aber erst, wenn man sich einen Docker-Swarm aufsetzt, damit diese Container dann auch Hoch verfügbar oder skalierbar sind.

Dazu habe ich mir in der Vergangenheit mal ein paar Gedanken gemacht. Ziel dieser Anleitung ist es nun meinerseits einmal ein mögliches, einfaches Szenario aufzuzeigen, mit dem man den Swarm für die Build-Prozesse nutzen kann.

Zielsetzung: Mit dem Swarm wird es möglich sein Buildserver mit persistenten Daten zu starten und variable Agenten in einer beliebigen Anzahl von Workern anzubinden. Dabei bekommt jeder Jenkinsmaster ein eigenes Netzwerk das er mit den Slaves nutzt um daten auzutauschen. So ist es u.a. möglich das die Slaves den Master einfach mit seinem Namen ansprechen können. Der Aufbau ist ersteinmal exemplarisch und bietet keine Ausfallsicherheit für die Jenkins Master, da die Daten persistent vorgehalten werden - das lässt sich aber leicht ändern.

Aufbau des swarms Der Swarm kann grundsätzlich ausschließlich aus managern bestehen, was die Ausfallsicherheit gewährleistet. Wenn wir dann allerdings sicherstellen wollen, dass die Jenkins Master nur auf einem Gerät laufen müssen wir mit Tags arbeiten. Nur so können wir ohne shared storage die Daten Konsitent halten.

Auf dem LEADER (1. Rechner)

docker swarm init --advertise-addr 192.168.XXX.YYY

Dann 

docker swarm join-token manager

und diese Anweisungen auf den anderen Rechner ausführen. Somit läuft der Swarm und hat auch schon eine Ausfallsicherheit.

Nun des ersten Rechner des Swarms als Jenkins-Master kennzeichnen:

docker node update --label-add JENKINS-MASTER SWAMNODE1
docker node update --label-add JENKINS-SLAVE SWARMNODE2 SWARMNODE3 ...

Nun ist es Zeit ein Netzwerk für den ersten Master zu erstellen:

docker network create --driver overlay jenkins-test-netzwerk

Dieses Netzwerk nutzen wir um den Datenverkehr zwischen den Slaves und dem Master zu kapseln.

Nun können wir eigentlich schon den ersten Jenkins-Master starten und geben ihm dabei sowohl das Netzwerk mit zu dem er verbunden ist, als auch das Volume indem die Daten gespeichert werden sollen:

Zuerst wird ein Volume angelegt in dem dann die Daten vorgehalten werden:

docker volume create jenkins-test
docker service create --name jenkins-test-master -p 8080:8080 -p 50000:50000 --network jenkins-test-netzwerk --network docker_gwbridge --placement-pref 'spread=node.labels.JENKINS-MASTER' -m source=jenkins-test,target=/var/jenkins_home jenkins

Somit findet sich laut der Dokumentation vom Jenkins-Image alles relevante (Plugins, workspaces, etc) ab jetzt in diesem externen Volume. Das kann natürlich auch gern mit bind-mounts genutzt werden.

Jetzt schon sollte es möglich sein den Jenkins unter der Adresse des Managers:8080 anzusprechen. Was nun noch fehlt sind die Worker. Hier könnten direkt deine images zum Einsatz gebracht werden. Da du dich besser mit auskennst - einfach mal die Unterschiede:

docker service create --name jenkins-slave --network jenkins-test-netzwerk --placement-pref 'spread=node.labels.JENKINS-SLAVE' --replicas 4 jenkins-slave

Auf diese Weise können die Slaves sich nur mit dem Jenkins verbinden. Dieser muss ihnen dann auch die Daten zur Verfügung stellen. Da da vielleicht nicht geht kann man das  --network dockergwbridge noch dazu packen.

Die Slaves können den Master aber nun durch die Verwendung eines eigenen Netzwerkes direkt mit dem Containernamen ansprechen - also jenkins-test-master. Das macht das Verbinden und zuordnen einfacher, wenn man sich vorstellt, dass man das vielleicht Skripten will.

Jetzt ist es ja eigentlich schon mal cool, das man einfach auf diese Ressourcen zugreifen kann und die Laufzeitumgebung gesteuert wird. Auch ist es ja erst mal cool, dass wir den Jenkins unter dem Port ansprechen können.

Wenn man nun einen Schritt weiter gehen wollte, dann haut man sich noch einen Reverseproxy davor - wie zum Beispiel Traefik (macht auch schöne bunte Bilder).

Wenn man jetzt noch die Datenhaltung gern auf alle Server verteilen möchte oder auf einem Storage ablegen will, oder sonst was tun möchte, dann kann das sogar fast schon während der Laufzeit passieren. und man kann so den bestehenden Swarm ausbauen.

Fazit Diese Überlegungen sind schon etwas älter und mit einem Kubernetes-Plugin samt Cluster ist die Aufgabe auch schon fast gelöst. Allerdings bemerke ich immer wieder, das Docker Swarm einfach sexyer ist was die simplicity angeht und auch der Overhead ist nicht so enorm. Zwar ist dieses Beispiel noch nicht fertig - aber es zeigt wie einfach man seinen Kram in einen Docker-Swrm verfrachten und so mit den großen Jungs am Tisch mitreden kann.


Wie man nachträglich einen olcRootPW setzt und cn=config benutzt

5 Jun 2019 - Lesezeit: 3 Minuten

So manches Mal bin ich bei wirklich interessanter Software auf die Nase gefallen, weil ich die Dokumentation nicht zuende gelese habe. So zum Beispiel auch bei OpenLDAP.

Hier habe ich nämlich verpennt, dass man bei der Umtellung auf OLC auc einen weiteren Benutzer für die Konfiguration anlegen/angeben muss. Ohne diese Benutzer läuft alles, aber die Bearbeitung der Konfiguration schlägt dahingehend fehl, dass man sich nicht administrativ mit dem Pfad cn=config verbinden kann.

Da es sich aber um brave, gute Software handelt die einem Fehler verzeiht, ist es "natürlich" möglich sein eigenes Versagen zu korrigeren. Wenn auch nicht auf den ersten Blick ersichtlich.

Natürlich muss man sich ein Passwort erstellen, damit es vergeben kann. Dazu dient der folgende Aufruf:

slappasswd

Die Ausgabe muss man sich natürlich brav merken. Dann kann es weitergehen. Wir werden nämlich die Datei /etc/openldap/slapd.d/cn\=config/olcDatabase\={0}config.ldif bearbeiten und unseren Benutzer einfach so hinzufügen.

olcRootPW:: **SUPERDUPERSICHERESKENNWORTWASWIRUNSERSTELLTHABEN**
olcRootDN: cn=admin,cn=config

Somit weiss unser OpenLDAP zukünftig von dem Benutzer cn=admin,cn=config. Leider wird ein Neustart an dieser Stelle nicht funktionieren, da die Dateien mit einer Prüfsumme versehen sind, welche wir erst generieren und einpflegen müssen. Andernfalle schläfgt die Verarbeitung dieser Datei mit einer entsprechenden Meldung fehl.

yum install perl-Archive-Zip -y
tail -n +3 /etc/openldap/slapd.d/cn\=config/olcDatabase\=\{0\}config.ldif > /tmp/fixed.ldif
crc32 /tmp/fixed.ldif

Somit haben wir schon mal die neue Prüfsumme. Diese tragen wir dann in den Header der Datei selbst ein

vi /etc/openldap/slapd.d/cn\=config/olcDatabase\=\{0\}config.ldif

Anschließend kann der Dienst neu gestartet werden und alles ist wieder super duper gut.

Quellen und Links wie man OpenLDAP richtig machen kann:


OpenVSwitch GRE Tunnel zur VM Vernetzung

11 Mai 2019 - Lesezeit: 3 Minuten

Ich hatte in meinem Beitrag Promox auf einem Hetznerserver mit virtuellen Netzwerken beschrieben, wie man virtuelle Netzwerke auf einem Hypervisor mit Hilfe von Linux Bridges erstellt. Diese Netzwerke können dazu verwendet werden, eigene Infrastrukturen aufzubauen und so sehr isoliert VMs zu betreiben.

Wenn nun aber die Ressourcen eines Hosts zur Neige gehen und man einen weiteren Host aufstellt, dann kommt irgendwann vielleicht der Wunsch auf VMs übergreifend in einem dieser virtuellen Netzwerke betreiben zu können. Damit diese möglich ist, muss es aber eine Verbindung dieser beiden Bridges (Netzwerke) geben, welche die Kommunikation ermöglicht.

Dazu kann man super OpenVSwitch einsetzen. Dieses Projekt ist ohnhin sehr interessant, da es sich bei vielen Lösungen wiederfindet - so zum Beispiel auch bei Proxmox und OpenStack.

Damit man über Hardwaregrenzen hinweg ein virtuelles Netzwerk aufspannen kann, muss man sich erst einen virtuelle Switch aufbauen. Zur Sicherheit aktivieren ich auch gleich STP

ovs-vsctl add-br vmbr2
ovs-vsctl set bridge vmbr2 stp_enable=true

In diesem Switch packt man dann die Netzwerkkarten der virtuellen Maschinen.

 ovs-vsctl add-port vmbr2 tap100i2

Sobald dies auf beiden Hosts passiert ist, kann man mit Hilfe eines GRE Tunnels diese beiden Switches verbinden.

ovs-vsctl add-port vmbr2 gre1 -- set interface gre1 type=gre options:remote_ip=XXX.XXX.XXX.XXX

XXX.XXX.XXX.XXX ist natürlich die IP-Adresse des anderen Servers.

Und weil ich ein Fan von Proxmox bin und grundsätzlich schon recht bequem, hab ich keine Lust das jedes Mal von Hand zu machen und trage es daher einfach in die /etc/network/interfaces ein.

auto vmbr2
allow-ovs vmbr2
iface vmbr2 inet manual
    ovs_type OVSBridge
    post-up ovs-vsctl set bridge vmbr2 stp_enable=true
    post-up ovs-vsctl add-port vmbr2 gre1 -- set interface gre1 type=gre options:remote_ip=XXX.XXX.XXX.XXX

**Quellen und Links: *** http://docs.openvswitch.org/en/latest/faq/configuration/


Über

Ich bin manisch interessiert am Leben. An den Dingen die wir tun können und den Optionen die sich uns bieten. IT, Netzwerke und EDV im allgemeinen sind mein Steckenpferd: ich mache das einfach zu gern und bin gut darin zu kombinieren. Fotografie, Hunde, Jagd, Falknerei ist das, was mich vollständig macht. All diese Dinge gehören zu meinem Leben und ich genieße jeden Tag.