Ich habe zu Hause einen Cluster aus Raspberry Pis, auf dem Docker Swarm läuft. Damit alles im Gleichschritt bleibt, verwenden sie dieselbe Konfiguration – Benutzer, Docker-Versionen usw.
Manchmal erfordern Updates, dass auf allen Knoten des Clusters dasselbe ausgeführt wird – zum Beispiel das Anlegen eines neuen Docker-macvlan-Netzwerks.
Dafür muss man entweder dieselben Befehle auf allen Knoten manuell ausführen, indem man sich per ssh auf jeden einzelnen einloggt, die Befehle laufen lässt und dann zum nächsten weitergeht.
Da ich versuche, langfristig meinen Aufwand zu reduzieren und alles so ordentlich wie möglich zu halten, habe ich angefangen, nach Möglichkeiten zu suchen, Befehle auf allen Knoten gleichzeitig auszuführen.
Iteration 1: Eigenes Python-Skript
Die erste Iteration bestand darin, ein eigenes Python-Skript zu schreiben. Einerseits wollte ich dabei Python etwas besser lernen, andererseits fand ich keinen guten Weg, Befehle auf eine eher native Art auszuführen.
Wie zu erwarten war (ich habe schließlich noch wenig Erfahrung mit der Sprache 🙂 ), wurde es ziemlich schnell ein aufgeblähtes Durcheinander und war sehr anfällig für Fehler.
Ich musste einen anderen Weg finden, ohne mir ständig neu erarbeiten zu müssen, was ich vor drei Wochen gemacht hatte und was beim letzten Mal kaputtgegangen ist.
Iteration 2: pssh
Beim Herumgooglen bin ich auf [pssh](https://linux.die.net/man/1/pssh) gestoßen, das Dinge parallel über SSH ausführen kann.
Alles in allem war es ziemlich einfach, das Ganze zum Laufen zu bekommen.
Das Problem war, dass ich einige Dinge per sudo ausführen musste. Passwörter herumzureichen war nicht gerade ideal, also musste ich wieder suchen, wie ich das sudo-Passwort senden kann, wenn der entfernte Server danach fragt.
Es stellt sich heraus, dass es ziemlich einfach ist, wenn man über den richtigen StackOverflow-Kommentar stolpert.
Die Kurzfassung (TL;DR):
stty -echo; printf "Password: "; read PASS; stty echo; echo "${PASS}" | \
pssh -h <HOSTFILE> -o /tmp/output -t 0 -I "`cat ./commands.sh`"Das -I "`cat ./commands.sh`" muss genau so geschrieben werden (in Anführungszeichen und Backticks eingefasst), sonst werden die Befehle nicht richtig ausgeführt. Das Passwort wird als separater Befehl gesendet und nicht als Eingabe für sudo aufgenommen.
Der andere Haken ist, dass man wegen dieser Konstruktion sudo mit dem Parameter -S ausführen muss, damit die Passworteingabe korrekt entgegengenommen wird.