Um experimento

Um experimento

sleepé um substituto para os processos mais complexos, é claro.

Este Dockerfile (como você pode ver usando o formulário exec para que haja apenas um processo em execução e nenhum filho de bash):

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

cria um contêiner ininterrupto:

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

Quando tento parar:

time docker stop kill-sleep

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

o comando expira em 10 segundos antes que o contêiner seja eliminado.

O problema não é que ele sleepnão processa sinais, porque se eu executar no host:

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

o processo para imediatamente.

O problema pode ter a ver com o fato de estar rodando como PID 1 no contêiner, mas ainda não vi uma documentação de referência para isso.

Responder1

Quando você corre docker stop ...,algumas coisas vão acontecer:

  1. dockerenvia um SIGTERMpara o processo principal do contêiner. O processo é capaz de mascarar/ignorar a SIGTERM, e se o fizer (ou manuseá-lo sem encerrar) "nada" acontecerá.
  2. Após um tempo limite (padrão 10 segundos), dockerenvia um SIGKILLpara o processo principal. Este sinal não pode ser mascarado por um processo e, portanto, morre imediatamente, sem oportunidade de executar um procedimento de desligamento.

Idealmente, os processos executados dockerresponderão SIGTERMem tempo hábil, cuidando de qualquer limpeza antes de encerrar.

Se você sabe que o processo não tem nenhuma manutenção para realizar (por exemplo: sleep) ou não responderá adequadamente a SIGTERM, você pode especificar um tempo limite mais curto (ou mais longo) com o -tsinalizador:

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

Por exemplo, no seu caso, você pode querer executar docker stop -t 0 ${CONTAINER}.


A razão pela qual este comportamento do sinal é diferente é devido ao sleepfuncionamento com PID = 1.

Normalmente (por exemplo: executando com PID! = 1), qualquer sinal de que o processo não lida explicitamente leva ao encerramento do processo - tente enviar um sleepa SIGUSR1.

No entanto, ao executar com PID = 1, os sinais não tratados são ignorados, caso contrário, você acabaria com um kernel panic:

Kernel panic - not syncing: Attempted to kill init!

Você pode enviar um sinal para o contêiner do docker usando ferramentas do docker, por exemplo:

docker kill -s TERM kill-sleep

Como podemos ver, isso não tem o efeito desejado, mas sim:

docker kill -s KILL kill-sleep

Um experimento

Dockerfile

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

correr.sh

#!/bin/sh

echo "sleeping"
sleep 100000

Agora, corra

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

E isso em um terminal diferente:

docker stop kill-sleep

Observamos o mesmo atraso/tempo limite de 10 segundos.

Uma solução

Agora vamos lidar com o SIGTERM. Background e waiting for sleepsão devidos à forma como um shell POSIX lida com sinais (vejaessepara mais).

correr.sh

#!/bin/sh

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

echo "sleeping"
sleep 100000 &
wait

Execute os comandos novamente e veremos o que procuramos!

$ time docker stop kill-sleep
kill-sleep

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

Responder2

Mais algumas opções:

  • adicione a --initopção ao comando de execução do contêiner. Dessa forma, sleep não é PID 1 e init faz a coisa certa em TERM.
  • adicione o --stop-signal=KILLao comando de execução do contêiner. Entretanto, usar KILL como uma operação normal é geralmente desencorajado.

informação relacionada