
sleep
ist natürlich ein Ersatz für die komplexesten Prozesse.
Dieses Dockerfile (wie Sie sehen, wird das Exec-Formular verwendet, sodass nur ein Prozess ausgeführt wird und keine untergeordneten Prozesse bash
):
FROM busybox
CMD ["/bin/sleep", "100000"]
erstellt einen unterbrechungsfreien Container:
docker build -t kill-sleep .
docker run --rm --name kill-sleep kill-sleep
Wenn ich versuche, es zu stoppen:
time docker stop kill-sleep
kill-sleep
real 0m10.449s
user 0m0.021s
sys 0m0.027s
Der Befehl läuft 10 Sekunden vor dem Beenden des Containers ab.
Das Problem ist nicht, dass sleep
keine Signale verarbeitet werden, denn wenn ich es auf dem Host ausführe:
sleep 100000
# in another shell
ps faxww | grep sleep
kill -TERM 31333 # the PID
der Vorgang wird sofort beendet.
Das Problem hängt möglicherweise damit zusammen, dass dies im Container als PID 1 ausgeführt wird, aber ich habe dazu noch keine Referenzdokumentation gesehen.
Antwort1
Wenn du rennst docker stop ...
,einige Dinge werden passieren:
docker
sendet eineSIGTERM
an den Hauptprozess des Containers. Der Prozess kann eine maskieren/ignorierenSIGTERM
, und wenn er dies tut (oder es verarbeitet, ohne sich zu beenden) "Nichts" wird passieren.- Nach einer Zeitüberschreitung (Standard 10 Sekunden)
docker
wird ein Signal an den Hauptprozess gesendetSIGKILL
. Dieses Signal kann nicht von einem Prozess maskiert werden und wird daher sofort beendet, ohne dass die Möglichkeit besteht, ein Herunterfahrverfahren auszuführen.
docker
Im Idealfall reagieren die darin ausgeführten Prozesse SIGTERM
zeitnah darauf und kümmern sich um alle organisatorischen Schritte, bevor sie beendet werden.
Wenn Sie wissen, dass der Prozess entweder keine Verwaltungsaufgaben zu erledigen hat (z. B.: sleep
) oder nicht richtig auf reagiert , können Sie mit dem Flag SIGTERM
ein kürzeres (oder längeres) Timeout angeben :-t
-t, --time=10 Seconds to wait for stop before killing it
In Ihrem Fall möchten Sie beispielsweise gerne ausführen docker stop -t 0 ${CONTAINER}
.
Der Grund für das unterschiedliche Signalverhalten liegt im sleep
Betrieb mit PID = 1.
Normalerweise (z. B.: beim Ausführen mit PID != 1) führt jedes Signal, mit dem sich der Prozess nicht explizit befasst, zur Beendigung des Prozesses – versuchen Sie, ein sleep
a zu senden SIGUSR1
.
Beim Ausführen mit PID = 1 werden jedoch nicht verarbeitete Signale ignoriert, da es sonst zu einer Kernel-Panik kommen würde:
Kernel panic - not syncing: Attempted to kill init!
Sie können mithilfe von Docker-Tools ein Signal an den Docker-Container senden, zum Beispiel:
docker kill -s TERM kill-sleep
Wie wir sehen können, hat dies nicht den gewünschten Effekt, wohingegen dies den Effekt hat:
docker kill -s KILL kill-sleep
Ein Experiment
Docker-Datei
FROM busybox
COPY run.sh /run.sh
RUN chmod +x /run.sh
CMD "/run.sh"
ausführen.sh
#!/bin/sh
echo "sleeping"
sleep 100000
Jetzt lauf
docker build -t kill-sleep .
docker run --rm --name kill-sleep kill-sleep
Und dies in einem anderen Terminal:
docker stop kill-sleep
Wir beobachten dieselbe Verzögerung/Zeitüberschreitung von 10 Sekunden.
Eine Lösung
Nun wollen wir uns mit dem befassen SIGTERM
. Hintergrund und wait
ing for sleep
hängen davon ab, wie eine POSIX-Shell Signale verarbeitet (sieheDasfür mehr).
ausführen.sh
#!/bin/sh
die_func() {
echo "oh no"
sleep 2
exit 1
}
trap die_func TERM
echo "sleeping"
sleep 100000 &
wait
Führen Sie die Befehle erneut aus, und wir sehen, wonach wir suchen!
$ time docker stop kill-sleep
kill-sleep
real 0m2.515s
user 0m0.008s
sys 0m0.044s
Antwort2
Weitere Optionen:
- Fügen Sie den
--init
Schalter zum Container-Ausführungsbefehl hinzu. Auf diese Weise ist sleep nicht PID 1 und init macht bei TERM das Richtige. - fügen Sie den
--stop-signal=KILL
Befehl zum Ausführen des Containers hinzu. Von der Verwendung von KILL als einigermaßen normaler Vorgang wird jedoch im Allgemeinen abgeraten.