Ich habe einen Server unter Ubuntu 20.04 laufen, auf den per git eine
Website deployt werden soll. Aus den mit git push ins Repo übertragenen
Daten soll automatisch ein Docker-Image erzeugt werden.
Ich habe dazu ein bash-Skript geschrieben, das alle 10 sec prüft, ob
eine vom git-hook post-receive geschriebene Datei existiert und ggf. die
darin enthaltenen Kommandos ausführt und die Datei löscht.
Das funktioniert so weit.
Jetzt würde ich gerne dieses Skript automatisch starten, wenn das
home-Verzeichnis auf dem Server per sftp oder per ssh geöffnet wird. Das
Skript soll aber nur genau einmal laufen und sich verabschieden, wenn
niemand mehr eingeloggt ist.
Wie stellt man das am besten an?
Taucher schrieb:> Jetzt würde ich gerne dieses Skript automatisch starten, wenn das> home-Verzeichnis auf dem Server per sftp oder per ssh geöffnet wird.
Du könntest zum Beispiel mit entr die atime überprüfen. Bei
Verzeichnissen geht das aber nur in einer Loop.
Zum Beispiel:
while true; do ls home/* | entr -pd <was auch immer du damit vorhast>;
done
Taucher schrieb:> Ich habe einen Server unter Ubuntu 20.04 laufen, auf den per git eine> Website deployt werden soll. Aus den mit git push ins Repo übertragenen> Daten soll automatisch ein Docker-Image erzeugt werden.
Soweit so Normal, die meisten verwenden für sowas eine CI/CD Pipeline,
Jenkins und Gitlab oder nur Gitlab sind da weit verbreitet.
Taucher schrieb:> Ich habe dazu ein bash-Skript geschrieben, das alle 10 sec prüft, ob> eine vom git-hook post-receive geschriebene Datei existiert und ggf. die> darin enthaltenen Kommandos ausführt und die Datei löscht.>> Das funktioniert so weit.
Die Erfahrung sagt, das klingt aus mehreren Gründen falsch. Die
Wichtigsten sind:
1.) Du machst Busy Waiting, Dein Bash script wird die meiste Zeit nichts
zu tun haben, aber um das zu Prüfen muss es immer mal wieder den
Prozessor bemühen. Warum lässt Du den post-receive hook nicht gleich das
Script starten oder arbeitest notfalls mit iNotify.
2.) unter Umständen kommt es hier zu einer Privilege escalation wenn der
Prozess mehr rechte hat als der Benutzer, welche die Befehle in die
Datei tut. Mit genügend krimineller Energie, kann der Benutzer das
System benutzen, um dauerhaft die gleichen rechte zu bekommen wie der
Prozess.
3.) das Umgehen Löschen nach dem Ausführen, klingt auch aus
unterschiedlichen Gründen fehleranfällig. Was passiert, wenn das Löschen
nicht klappt, weil das Script abbricht? Nach 10 Sekunden kommt dann der
nächste Bash lauf und so weiter...
Was wenn das Scipt durchläuft aber einen Fehler macht, kann ich das
Script irgendwo zu debug zwecken sehen?
Taucher schrieb:> Jetzt würde ich gerne dieses Skript automatisch starten, wenn das> home-Verzeichnis auf dem Server per sftp oder per ssh geöffnet wird. Das> Skript soll aber nur genau einmal laufen und sich verabschieden, wenn> niemand mehr eingeloggt ist.
Denn Teil verstehe ich nicht, meinst Du das Bash Script das alle 10
Sekunden pollt, oder das Script mit den Befehlen welches Dir, der
post-receive hook erzeugt oder was ganz anderes.
Was meinst Du mit das Script soll genau einmal laufen und sich
verabschieden, ich denke das post-receive Skript löscht sich, wenn des
erfolgreich war. Und so ein wenig widerspricht sich das einmal laufen
auch mit den" und sich verabschieden, wenn niemand mehr eingeloggt ist."
ist Dein ominöse Skript vielleicht ein Dämon der die ganze Zeit läuft?
Taucher schrieb:> Wie stellt man das am besten an?
systemd/User https://wiki.archlinux.org/title/systemd/User) vielleicht,
dort ein oneshot bauen der wird genau einmal gestartet, wenn sich der
Benutzer einloggt.
Ich bin mir aber nicht sicher, ob Deine Architektur, so eine gute Idee
ist. Vielleicht gehst Du vorher nochmal zurück ans Zeichenbrett und
siehst Dir an wie andere eine ähnliche Architektur gebaut haben. Ich
vermute mit einer gut geplanten CI/CD Pipeline, wird sich Deine aktuelle
Fragestellung wahrscheinlich nicht ergeben.
MaWin schrieb:> Ich mache das deploy direkt aus dem post-update hook heraus.
Das hat nur den Nachteil, dass dann die git-Verbindung so lange gesperrt
ist, bis das Generierungsskript fertig ist. Das dauert in meinem Fall.
Ich hatte auch schon versucht, aus dem git-Hook heraus das Skript
einfach in den Hintergrund zu schieben, das hat aber aus unklaren
Gründen nicht funktioniert.
Imonbln schrieb:> Soweit so Normal, die meisten verwenden für sowas eine CI/CD Pipeline,> Jenkins und Gitlab oder nur Gitlab sind da weit verbreitet.
Ich mache es ohne Github & Co. mit einem einfachen git push.
> Die Erfahrung sagt, das klingt aus mehreren Gründen falsch. Die> Wichtigsten sind:
Ist es aber nicht…
> 1.) Du machst Busy Waiting, Dein Bash script wird die meiste Zeit nichts> zu tun haben, aber um das zu Prüfen muss es immer mal wieder den> Prozessor bemühen.
Na ja, alle 10 sec nachsehen und dann wieder sleep würde ich nicht als
Busy Waiting bezeichnen… Innerhalb der 10 sec kommt genug Rauschen von
außen rein, dass die CPU immer wieder aktiv werden muss.
> Warum lässt Du den post-receive hook nicht gleich das> Script starten oder arbeitest notfalls mit iNotify.
S.o.
> 2.) unter Umständen kommt es hier zu einer Privilege escalation wenn der> Prozess mehr rechte hat als der Benutzer, welche die Befehle in die> Datei tut. Mit genügend krimineller Energie, kann der Benutzer das> System benutzen, um dauerhaft die gleichen rechte zu bekommen wie der> Prozess.
Das ist eine ziemlich theoretische Gefahr: in diesem Fall müsste sich
der Hacker auf dem Server einloggen, was voraus setzt, dass er die
Zugangsdaten kennt. Damit könnte er aber auf dem Server sowieso tun und
lassen, was er will…
> 3.) das Umgehen Löschen nach dem Ausführen, klingt auch aus> unterschiedlichen Gründen fehleranfällig. Was passiert, wenn das Löschen> nicht klappt, weil das Script abbricht? Nach 10 Sekunden kommt dann der> nächste Bash lauf und so weiter...
Schon mal was von Fehlerbehandlung gehört? Die soll es angeblich auch in
der bash geben ;-)
> Was wenn das Scipt durchläuft aber einen Fehler macht, kann ich das> Script irgendwo zu debug zwecken sehen?
Weißt du, was man unter "logging" versteht?
> Denn Teil verstehe ich nicht, meinst Du das Bash Script das alle 10> Sekunden pollt, oder das Script mit den Befehlen welches Dir, der> post-receive hook erzeugt oder was ganz anderes.
Nochmal zum mitmeißeln:
- Das Skript, um das es hier geht, läuft in einer unendlichen Schleife
und
guckt alle 10 sec nach, ob was zu tun ist
- Dieses Skript soll automatisch starten, wenn eine sftp- oder
ssh-Verbindung aufgebaut wird und terminieren, wenn die letzte
Verbindung
abgebrochen wurde.
- Das Signal, dass was zu tun ist, ist die Datei mit den auszuführenden
Kommandos, die der git-Hook schreibt.
Damit habe ich das ssh-/sftp-Login als Authentifizierungsprozess vor die
ganze Sache gestellt. Damit sollten keine über das übliche Maß hinaus
gehenden Sicherheitsprobleme entstehen.
Imonbln schrieb:> systemd/User https://wiki.archlinux.org/title/systemd/User) vielleicht,> dort ein oneshot bauen der wird genau einmal gestartet, wenn sich der> Benutzer einloggt.
Das ist ein guter Tipp. Jetzt muss ich nur noch herausbekommen, wie man
das 10-sec-Skript dort verdrahten muss.
Hm, mir scheint, systemd/User ist für dieses Problemchen etwas
überdimensioniert.
ps kann den User-Namen ausgeben – damit kann das 10-sec-Skript
feststellen, wieviele Prozesse unter diesem Namen noch laufen. Wenn es
nur noch einer – er selbst – ist, dann verabschiedet es sich und das
Terminierungsproblem ist gelöst.
Starten kann man das Skript aus ~/.bash_profile heraus. Die wird bei
jedem Login über ssh abgearbeitet. Das Skript stellt fest, ob schon eine
Instanz läuft. Wenn nein, schickt es sich selbst in den Hintergrund und
wenn ja, terminiert es stillschweigend.
Die Hintergrund-Instanz schreibt ihre PID in eine Datei in /tmp – dort
können weitere Instanzen nachsehen (und mit ps prüfen, ob ein Prozess
mit der dort vermerkten PID existiert).
Jetzt weiß ich nur noch nicht, ob der automatische Start auch mit sftp
funktioniert.
Taucher schrieb:> MaWin schrieb:>> Ich mache das deploy direkt aus dem post-update hook heraus.>> Das hat nur den Nachteil, dass dann die git-Verbindung so lange gesperrt> ist, bis das Generierungsskript fertig ist. Das dauert in meinem Fall.>> Ich hatte auch schon versucht, aus dem git-Hook heraus das Skript> einfach in den Hintergrund zu schieben, das hat aber aus unklaren> Gründen nicht funktioniert.
Das solltest du dir weiter anschauen. Hast du schonmal versucht das
Skript mit nohup in den Hintergrund zu schicken?
JE schrieb:> Das solltest du dir weiter anschauen. Hast du schonmal versucht das> Skript mit nohup in den Hintergrund zu schicken?
Das habe ich eben probiert – funktioniert leider nicht, egal ob per
Taucher schrieb:> Das habe ich eben probiert – funktioniert leider nicht, egal ob per
Hast du mehr Infos was nicht geht?
Du könntest die Ausgabe der Scripte auch mal auffangen.
Statt bash -c macht bash -lic oft viel besser.
JE schrieb:> Hast du mehr Infos was nicht geht?
Ich sehe nur mit ps, dass das Skript nach dem git push nicht läuft.
> Statt bash -c macht bash -lic oft viel besser.
Die -i-Option macht die Shell interaktiv – das ist das Skript aber
definitiv nicht.
Taucher schrieb:>> Statt bash -c macht bash -lic oft viel besser.>> Die -i-Option macht die Shell interaktiv – das ist das Skript aber> definitiv nicht.
Das -i stellt der Shell auch einen STDIN zur Verfügung und führt andere
Login Scripte aus, eventuell benötigt dein Script das. Das -l führt die
Login Scripte aus - vielleicht wird dort ein Pfad gesetzt der benötigt
wird.
Solange wir nicht sehen was die Scripte ausgeben ist das aber alles
rumraterei. Ersetze doch mal die ganzen /dev/null Umleitungen durch
>> /tmp/logfile.txt 2>&1
und schau nach was angemeckert wird.
Ich bin mir bei den Git-Hooks jetzt nicht ganz sicher - aber sind die
Scripte ausführbar?
JE schrieb:> Ich bin mir bei den Git-Hooks jetzt nicht ganz sicher - aber sind die> Scripte ausführbar?
Die Skripte sind alle ausführbar. Wenn ich nach einem git push das
Generierungsskript zu Fuß anwerfe, läuft alles durch und die Änderungen
greifen.
Taucher schrieb:> ps kann den User-Namen ausgeben – damit kann das 10-sec-Skript> feststellen, wieviele Prozesse unter diesem Namen noch laufen. Wenn es> nur noch einer – er selbst – ist, dann verabschiedet es sich und das> Terminierungsproblem ist gelöst.
Ich gebe Zehn von Zehn Frickelpunkten
Oh sorry, oben ist mir die Formatierung kaputt gegangen
```
/Pfad/zum/Script >> /tmp/logfile.txt 2>&1
```
schreibt die die Ausgabe des Scipts in eine Datei.
in meinem früheren leben habe ich das deployment über gitlab-ci in zwei
branches (dev, prod) durchgeführt.
bei einem push in den jeweiligen branch wurde ein deploy script
(normales shell script) ausgeführt. die anzahl der auszuführenden
scripts ist dabei variabel.
Taucher schrieb:> JE schrieb:>> Das solltest du dir weiter anschauen. Hast du schonmal versucht das>> Skript mit nohup in den Hintergrund zu schicken?>> Das habe ich eben probiert – funktioniert leider nicht, egal ob per> nohub skript </dev/null &>/dev/null &> oder mit nohub bash -c skript </dev/null &>/dev/null &
Es heißt ja auch "nohup" mit P und nicht mit B. Wie in "no hangup".
Nop schrieb:> Es heißt ja auch "nohup" mit P und nicht mit B. Wie in "no hangup".
Oh, das war die Gurke… Jetzt läuft das Generierungsskrip aus dem
git-hook heraus, danke für den Hinweis.
Damit ist mein 10-sec-Skript überflüssig. Dank an alle, die Tipps
geliefert haben.
Taucher schrieb:> Jetzt würde ich gerne dieses Skript automatisch starten, wenn das> home-Verzeichnis auf dem Server per sftp oder per ssh geöffnet wird. Das> Skript soll aber nur genau einmal laufen und sich verabschieden, wenn> niemand mehr eingeloggt ist.
Ich hab nicht so richtig verstanden, was du willst. Wenn sich jemand
einlogt, soll ein Skript ausgeführt werden, das einen Docker-Image
erstellt? Und wenn sich der letzte auslogt, soll das Skript gekillt
werden? Oder was meinst du mit "sich verabschieden"?
> Ich habe dazu ein bash-Skript geschrieben, das alle 10 sec prüft, ob> eine vom git-hook post-receive geschriebene Datei existiert und ggf. die> darin enthaltenen Kommandos ausführt und die Datei löscht.
Das könnte man vermutlich mit inotifywait geschickter machen. Damit
kannst du auf Änderungen warten, ohne sie explizit abfragen zu müssen.
Rolf M. schrieb:> Das könnte man vermutlich mit inotifywait geschickter machen.
Oder incrond... ;-)
Aber, sorry, für mich hört sich der ganze Anwendungsfall ein bisschen...
komisch an, wie dreimal um die Ecke gedacht und sich am Ende dann doch
sehenden Auges in beide Füße, ein Knie und ein Ohr geschossen. Wird aber
wohl an mir liegen...