概要
PHP8のDockerコンテナに対して
docker stop
や
docker-compose stop
をしてもSIGTERMが送られず
phpスクリプトに記載のシグナル制御がうまく動かなかった。
原因
利用したDocker ImageにてSTOPSIGNALによりデフォルトのSIGTERMから別のシグナルに変更されていたため。
詳細
Docker Image
docker-compose
version: '2.0'
services:
app:
container_name: php8
image: phpdockerio/php80-fpm
volumes:
- ./:/var/www/html/
command: php /var/www/html/test.php
test.php
<?php
pcntl_async_signals(true);
pcntl_signal(SIGTERM, 'hoge');
while(true){
echo("call\n");
sleep(2);
}
function hoge($signo){
echo("hoge call\n");
echo("{$signo}\n");
exit;
}
うまくいかない実行
docker-compose up
Starting php8 ... done
Attaching to php8
php8 | call
php8 | call
php8 | call
php8 | call
・・・
無限ループ中に別ターミナルからdockerを停止。
docker-compose stop
Stopping php8 ... done
$ docker-compose up
Starting php8 ... done
Attaching to php8
php8 | call
php8 | call
php8 | call
php8 | call
php8 exited with code 137
すぐに終了せずに10秒後にSIGKILLが送られて強制終了。
SIGTERMをキャッチしてくれない。
うまくいく実行
コンテナを起動しておく。
別ターミナルでそのコンテナに入る。
docker exec -it php8 bash
# プロセス一覧からtest.phpをシグナルを15でkillする例
ps aux | grep test.php | grep -v grep | awk '{print $2}' | xargs kill -15
これを送ると
$ docker-compose up
Starting php8 ... done
Attaching to php8
php8 | call
php8 | hoge call
php8 | 15
php8 exited with code 0
SIGTERM(signo=15)を受け取って即時に終了する。
試したこと
全てのシグナルをキャッチしてみる。
<?php
pcntl_async_signals(true);
for($i=1;$i<65;$i++){
// このあたりは上書き不可のシグナル
if($i===9)continue;
if($i===19)continue;
if($i===32)continue;
if($i===33)continue;
pcntl_signal($i, 'hoge');
}
while(true){
echo("call\n");
sleep(2);
}
function hoge($signo){
echo("hoge call\n");
echo("{$signo}\n");
exit;
}
実行してみたところ
$ docker-compose up
Starting php8 ... done
Attaching to php8
php8 | call
php8 | hoge call
php8 | 3
php8 exited with code 0
signo=3を受け取って終了した。
signo=3はSIGQUIT
https://www.php.net/manual/ja/pcntl.constants.php
考察
なんでdocker stopでSIGQUITを送ってるんだ?
デフォルトだとSIGTERMって書いてあるんだけど…。
https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/stop/
コンテナー内部の主となるプロセスは、シグナルSIGTERMを受信します。 そして一定時間後にSIGKILLを受信します。
ここで気になる記載が
初回に受信するシグナルは、コンテナーの Dockerfile 内においてSTOPSIGNAL命令を使って変更できます。
ほう、ってことはSTOPSIGNALで上書きしてる可能性あるか?
↓
使ってるimageのDockerfileを確認しに行く。
https://hub.docker.com/r/phpdockerio/php80-fpm/tags
https://hub.docker.com/layers/phpdockerio/php80-fpm/latest/images/sha256-5fc31be3e13612fa4a694f64937c267053cd187369f8ec28e335f4bc63abfe5a?context=explore
STOPSIGNAL SIGQUIT
シグナル上書きしてるぅ!
状況を理解した。
まとめ
適当に使わず、使ってるImageはよく確認しよう。