
sleep
Por 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 sleep
no 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:
docker
envía unSIGTERM
al proceso principal del contenedor. El proceso puede enmascarar/ignorar unSIGTERM
, y si lo hace (o lo maneja sin terminar) "nada" pasará.- Después de un tiempo de espera (predeterminado 10 segundos),
docker
envía unSIGKILL
al 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 docker
responderán de SIGTERM
manera 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 -t
bandera:
-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 sleep
funciona 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 sleep
a 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 wait
el ing sleep
se 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
--init
modificador 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=KILL
comando de ejecución del contenedor. Sin embargo, generalmente se desaconseja el uso de KILL como una operación algo normal.