Ich habe festgestellt, dass viele entrypoint.sh-Skripte für Docker ungefähr Folgendes tun:
#!/bin/bash
set -e
... code ...
exec "$@"
Wofür sind die set -e
und die exec "$@"
?
Antworten:
Grundsätzlich werden alle übergebenen Befehlszeilenargumente entrypoint.sh
als Befehl ausgeführt. Die Absicht ist im Grunde "Alles in diesem .sh-Skript tun, dann in derselben Shell den Befehl ausführen, den der Benutzer in der Befehlszeile übergibt".
Sehen:
exec "$@"
der aktuell ausgeführte Prozess durch den neuen Prozess ersetzt wird, der für die übergebenen Argumente erzeugt wurde. Wichtig für die Docker-Signalisierung: stackoverflow.com/a/32261019/99717
set -e
Legt eine Shell-Option fest, die sofort beendet wird, wenn ein ausgeführter Befehl mit einem Exit-Code ungleich Null beendet wird. Das Skript wird mit dem Exit-Code des fehlgeschlagenen Befehls zurückgegeben. Von der Bash-Manpage:
set -e:
Beenden Sie das Programm sofort, wenn eine Pipeline (die aus einem einzelnen einfachen Befehl bestehen kann), eine Liste oder ein zusammengesetzter Befehl (siehe SHELL GRAMMAR oben) mit einem Status ungleich Null beendet wird. Die Shell wird nicht beendet, wenn der fehlgeschlagene Befehl Teil der Befehlsliste unmittelbar nach einer Weile oder bis zum Schlüsselwort ist, Teil des Tests nach den reservierten if- oder elif-Wörtern, Teil eines Befehls, der in einem && oder || ausgeführt wird Liste mit Ausnahme des Befehls nach dem letzten && oder ||, eines Befehls in einer Pipeline außer dem letzten oder wenn der Rückgabewert des Befehls mit! invertiert wird. Wenn ein anderer zusammengesetzter Befehl als eine Subshell einen Status ungleich Null zurückgibt, weil ein Befehl fehlgeschlagen ist, während -e ignoriert wurde, wird die Shell nicht beendet. Ein Trap auf ERR wird, falls gesetzt, ausgeführt, bevor die Shell beendet wird.
Wenn ein zusammengesetzter Befehl oder eine Shell-Funktion in einem Kontext ausgeführt wird, in dem -e ignoriert wird, wird keiner der im zusammengesetzten Befehl oder Funktionskörper ausgeführten Befehle von der Einstellung -e beeinflusst, selbst wenn -e festgelegt ist und ein Befehl a zurückgibt Fehlerstatus. Wenn ein zusammengesetzter Befehl oder eine Shell-Funktion -e während der Ausführung in einem Kontext setzt, in dem -e ignoriert wird, hat diese Einstellung keine Auswirkung, bis der zusammengesetzte Befehl oder der Befehl, der den Funktionsaufruf enthält, abgeschlossen ist.
exec "$@"
wird normalerweise verwendet, um den Einstiegspunkt zu einem Durchlauf zu machen, der dann den Docker-Befehl ausführt. Es ersetzt die aktuell ausgeführte Shell durch den Befehl, auf den "$@"
verwiesen wird. Standardmäßig zeigt diese Variable auf die Befehlszeilenargumente.
Wenn Sie ein Bild mit einem Einstiegspunkt haben, der auf entrypoint.sh zeigt, und Sie Ihren Container als ausführen, bedeutet dies docker run my_image server start
, dass er entrypoint.sh server start
im Container ausgeführt wird. In der Exec-Zeile ersetzt entrypoint.sh
sich die als PID 1 ausgeführte Shell durch den Befehl server start
.
Dies ist für die Signalverarbeitung von entscheidender Bedeutung. Ohne Verwendung würde exec
das server start
im obigen Beispiel als eine andere PID ausgeführt, und nach dem Beenden würden Sie zu Ihrem Shell-Skript zurückkehren. Bei einer Shell in PID 1 wird ein SIGTERM standardmäßig ignoriert. Das bedeutet, dass das ordnungsgemäße Stoppsignal, docker stop
das an Ihren Container gesendet wird, vom server
Prozess niemals empfangen wird. Nach 10 Sekunden (standardmäßig) docker stop
würde das ordnungsgemäße Herunterfahren aufgegeben und ein SIGKILL gesendet, das das Beenden Ihrer App erzwingt. Bei potenziellem Datenverlust oder geschlossenen Netzwerkverbindungen hätten App-Entwickler möglicherweise herumcodieren können, wenn sie das Signal empfangen hätten. Dies bedeutet auch, dass Ihr Container immer 10 Sekunden braucht, um anzuhalten.
Beachten Sie, dass Sie mit Shell-Befehlen wie shift
und set --
den Wert von ändern können "$@"
. Beispiel: Hier ist ein kurzer Teil eines Skripts, das /bin/sh -c "..."
den Befehl entfernt, der angezeigt werden kann, wenn Sie die Shell-Syntax von Docker verwenden für CMD
:
# convert `/bin/sh -c "server start"` to `server start`
if [ $# -gt 1 ] && [ x"$1" = x"/bin/sh" ] && [ x"$2" = x"-c" ]; then
shift 2
eval "set -- $1"
fi
....
exec "$@"
test
Spezifikation , die -a
veraltet markiert . [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]
ist der richtige Ersatz (es ist kein x"$1"
Hackery erforderlich, wenn nur die nicht veraltete Syntax verwendet wird).
shift 2; set -- $1
ist überhaupt nicht das gleiche wie, wie eval
die Zeichenfolge analysiert wird. Überlegen Sie /bin/sh -c 'printf "%s\n" "hello world" "goodbye world"'
, ob Sie einen konkreten Testfall wünschen und sehen, dass Bash beim Konvertieren einer Zeichenfolge in Argumente keine Anführungszeichen analysiert .
eval
, glaube ich, noch ich will , dass das Verhalten spiegelt /bin/sh -c
auf der Saite haben würde, aber lassen Sie es mich wissen , wenn ich etwas fehle.
set -e
- Skript beenden, wenn ein Befehl fehlschlägt (Wert ungleich Null)
exec "$@"
- leitet Eingangsvariablen um, mehr dazu hier
exec
Es gibt sicherlich einen Verwendungsmodus, in dem Umleitungen durchgeführt werden, aber dies ist nicht dieser Modus.
set -e
wird dies als weitaus fehleranfälliger angesehen als die handschriftliche Fehlerbehandlung ? (Wenn Sie es eilig haben, überspringen Sie die Analogie oben für die folgenden Übungen).