Un experimento

Un experimento

sleepPor supuesto, es un sustituto para los procesos más complejos.

Este Dockerfile (como puede ver usando el formulario ejecutivo para que solo haya un proceso en ejecución y no haya hijos de bash):

FROM busybox
CMD ["/bin/sleep", "100000"]

crea un contenedor ininterrumpible:

docker build -t kill-sleep .
docker run --rm --name kill-sleep kill-sleep

Cuando intento detenerlo:

time docker stop kill-sleep

kill-sleep
real    0m10.449s
user    0m0.021s
sys     0m0.027s

el comando se agota 10 segundos antes de que se elimine el contenedor.

El problema no es que sleepno maneja señales, porque si lo ejecuto en el host:

sleep 100000
# in another shell
ps faxww | grep sleep
kill -TERM 31333  # the PID

el proceso se detiene inmediatamente.

El problema puede tener que ver con el hecho de que se ejecuta como PID 1 en el contenedor, pero todavía tengo que ver una documentación de referencia para eso.

Respuesta1

Cuando corres docker stop ...,algunas cosas sucederan:

  1. dockerenvía un SIGTERMal proceso principal del contenedor. El proceso puede enmascarar/ignorar un SIGTERM, y si lo hace (o lo maneja sin terminar) "nada" pasará.
  2. Después de un tiempo de espera (predeterminado 10 segundos), dockerenvía un SIGKILLal proceso principal. Esta señal no puede ser enmascarada por un proceso y, por lo tanto, muere inmediatamente sin oportunidad de ejecutar un procedimiento de apagado.

Idealmente, los procesos que se ejecutan dentro dockerresponderán de SIGTERMmanera oportuna y se encargarán de cualquier limpieza antes de finalizar.

Si sabe que el proceso no tiene que realizar ninguna limpieza (por ejemplo: sleep) o no responderá correctamente SIGTERM, puede especificar un tiempo de espera más corto (o más largo) con la -tbandera:

-t, --time=10
    Seconds to wait for stop before killing it

Por ejemplo, en su caso, es posible que desee ejecutar docker stop -t 0 ${CONTAINER}.


La razón por la que el comportamiento de esta señal es diferente se debe a que sleepfunciona con PID = 1.

Normalmente (p. ej.: ejecutar con PID! = 1), cualquier señal que el proceso no trate explícitamente conduce a la finalización del proceso; intente enviar un sleepa SIGUSR1.

Sin embargo, cuando se ejecuta con PID = 1, las señales no controladas se ignoran; de lo contrario, terminarías con un pánico en el kernel:

Kernel panic - not syncing: Attempted to kill init!

Puede enviar una señal al contenedor de la ventana acoplable utilizando las herramientas de la ventana acoplable, por ejemplo:

docker kill -s TERM kill-sleep

Como podemos ver, esto no tiene el efecto deseado, mientras que esto sí:

docker kill -s KILL kill-sleep

Un experimento

archivo acoplable

FROM busybox
COPY run.sh /run.sh
RUN chmod +x /run.sh
CMD "/run.sh"

correr.sh

#!/bin/sh

echo "sleeping"
sleep 100000

ahora corre

docker build -t kill-sleep .
docker run --rm --name kill-sleep kill-sleep

Y esto en una terminal diferente:

docker stop kill-sleep

Observamos el mismo retraso/tiempo de espera de 10 segundos.

Una solución

Ahora manejemos el SIGTERM. Los antecedentes y waitel ing sleepse deben a cómo un shell POSIX maneja las señales (consulteestepara más).

correr.sh

#!/bin/sh

die_func() {
        echo "oh no"
        sleep 2
        exit 1
}
trap die_func TERM

echo "sleeping"
sleep 100000 &
wait

Ejecute los comandos nuevamente y veremos lo que buscamos.

$ time docker stop kill-sleep
kill-sleep

real    0m2.515s
user    0m0.008s
sys     0m0.044s

Respuesta2

Algunas opciones más:

  • agregue el --initmodificador al comando de ejecución del contenedor. De esta manera, dormir no es PID 1 e init hace lo correcto en TERM.
  • agregue el --stop-signal=KILLcomando de ejecución del contenedor. Sin embargo, generalmente se desaconseja el uso de KILL como una operación algo normal.

información relacionada