Ein Experiment

Ein Experiment

sleepist 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 sleepkeine 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:

  1. dockersendet eine SIGTERMan den Hauptprozess des Containers. Der Prozess kann eine maskieren/ignorieren SIGTERM, und wenn er dies tut (oder es verarbeitet, ohne sich zu beenden) "Nichts" wird passieren.
  2. Nach einer Zeitüberschreitung (Standard 10 Sekunden) dockerwird ein Signal an den Hauptprozess gesendet SIGKILL. Dieses Signal kann nicht von einem Prozess maskiert werden und wird daher sofort beendet, ohne dass die Möglichkeit besteht, ein Herunterfahrverfahren auszuführen.

dockerIm Idealfall reagieren die darin ausgeführten Prozesse SIGTERMzeitnah 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 SIGTERMein 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 sleepBetrieb 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 sleepa 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 waiting for sleephä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 --initSchalter 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=KILLBefehl zum Ausführen des Containers hinzu. Von der Verwendung von KILL als einigermaßen normaler Vorgang wird jedoch im Allgemeinen abgeraten.

verwandte Informationen