pojiro
#1
docker stop のSIGTERMの動作を調べるなかで理解できないケースがあり、相談させていただきたいです。
PID1 の bash プロセスを立ち上げ、
$ docker run --rm -it ubuntu:20.04 /bin/bash
root@552f11e3e2ce:/# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.3 0.0 4116 3336 pts/0 Ss 03:02 0:00 /bin/bash
root 9 0.0 0.0 5900 2892 pts/0 R+ 03:02 0:00 ps aux
以下のようにシグナルをトラップするようにした場合は、トラップが動作するのですが、
$ docker run --rm -it ubuntu:20.04 /bin/bash
root@141a8eced1bb:/# trap 'printf "TERM\n";' TERM && trap 'printf "EXIT\n";' EXIT
# 別コンソールで docker stop [conainer name]
root@141a8eced1bb:/# exit
TERM # TERMのトラップが動作
EXIT # EXITのトラップが動作
以下のようにシグナルをトラップするようにした場合は、トラップが動作しません。
$ docker run --rm -it ubuntu:20.04 /bin/bash
root@a8585f8f7b58:/# trap 'printf "TERM\n";' TERM
# 別コンソールで docker stop [conainer name]
root@a8585f8f7b58:/# exit
これはどうして動作しないのでしょうか?
「いいね!」 2
@pojiro さん、はじめまして!
docker stop
の TERM を使った処理は、通常のシェルで期待する動作にはならないようです。
理由としては、以下のページによりますと、PID 1 のプロセスは、コンテナ内でも Linux カーネルの特別な処理がされるため、TERM が機能しない場合がある、書かれています。
そのため、コンテナ内の bash で trap 'printf "TERM\n";' TERM
を実行していても、 docker stop
を実行しても何も処理されていないように見えます。
TERM をトラップするのが目的であれば、次のようにされてみてはいかがでしょうか。
docker run -t ubuntu:20.04 bash -c "trap 'printf \"TERM\n\";' TERM; read"
docker stop
を実行すると、docker run
を実行したコマンドライン上で TERM
の文字が見えると思います。
ちなみに、公式ドキュメントにもありますように、
ENTRYPOINT
スクリプトが Unix シグナルを受信し、続いて、他の処理を行うようにする必要があります。
停止時に様々な総理をするには、Dockerfile の ENTRYPOINT
で何らかの処理をするスクリプトを書く必要がある、とあります。
そこで、もしかすると、処理によっては、以下にあるようなスクリプトを組み合わせると、ご希望通りの動作になるかと思います。
「いいね!」 1
pojiro
#3
@zembutsu さん、はじめまして、ご回答・dumb-init
の紹介ありがとうございます!
回答いただいたキーワードから、docker run の --init オプション、そのオプションで使用されている tini を調べることができました!
ただ、今、私の関心は「 pidが1であっても明示的に trap を実装すればdocker stopの SIGTERM を捕捉できるはず」というところに有ります。
そこで、ご回答いただいたキーワード用いることで以下のページを見つけることができました。
https://raby.sh/sigterm-and-pid-1-why-does-a-container-linger-after-receiving-a-sigterm.html
そして、ページ内の /proc/<pid>/status
を解析するスクリプトを、先に提示したコンテナの起動直後のbash(trapコマンドは未実行)で実行したところ以下を得ました。
root@f602223fbcc2:~# cat > hoge.sh <<"END"
> #!/bin/bash
> # https://stackoverflow.com/a/61365083
>
> pid=${1:?Missing pid}
> cat /proc/$pid/status|egrep '(Sig|Shd)(Pnd|Blk|Ign|Cgt)'|while read name mask;do
> bin=$(echo "ibase=16; obase=2; ${mask^^*}"|bc)
> echo -n "$name $mask $bin "
> i=1
> while [[ $bin -ne 0 ]];do
> if [[ ${bin:(-1)} -eq 1 ]];then
> kill -l $i | tr '\n' ' '
> fi
> bin=${bin::-1}
> set $((i++))
> done
> echo
> done
> END
# 実行にはbc が必要だったので、別途 apt install しています
root@f602223fbcc2:~# /bin/bash hoge.sh 1
SigPnd: 0000000000000000 0
ShdPnd: 0000000000000000 0
SigBlk: 0000000000010000 10000000000000000 CHLD
SigIgn: 0000000000380004 1110000000000000000100 QUIT TSTP TTIN TTOU
SigCgt: 000000004b817efb 1001011100000010111111011111011 HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM CHLD XCPU XFSZ VTALRM WINCH SYS
(trapを未実行であるにも関わらず)SigCgtにすでに TERM が表示されています。現時点では、これが関係するのかなぁと想像しています。
まだまだ分からなそうですが、進展有りましたらここに追記していこうと思います。
とりいそぎ、以上です。
「いいね!」 3
@pojiro さん、情報ありがとうございます!
こちらのページの情報は知らなかったので、スクリプトとあわせて確認してみますね。
是非また何か分かりましたら共有いただけると、他の方のご参考にもなると思います
「いいね!」 1