DockerfileのCMDをShell形式で記述したらコンテナが停止しなくなってしまったので直した
UbuntuでPHP-FPMのイメージを作成する際に、CMDにPHP-FPMの起動コマンドをShell形式で書いたらdocker kill, Ctrl-Cでコンテナが終了しなくなってしまったので調べて修正しました。
FROM ubuntu:20.04 RUN apt update -qq && apt -y upgrade -qqy \ && DEBIAN_FRONTEND=noninteractive apt -qqy install php \ php-fpm \ && apt clean \ && rm -rf /var/lib/apt/lists/* CMD /usr/sbin/php-fpm7.4 -F -y /etc/php/7.4/fpm/php-fpm.conf
こういう感じでDockerfileを書いていたのですが、
docker run --rm ubuntu-php-fpm
のような形で起動したところ、docker killやCtrl-Cでコンテナが終了しなくなってしまいました。 CentOS7のイメージではうまくいったのに...!?
- 起動コマンドをShell形式で書いていたこと
- Ubuntuのイメージを使用していたこと
上記に点が今回の事象原因のようでした。
起動コマンドをShell形式で書いていた
CMD 命令にはShell形式とExec形式があります。 ※今回はENTRYPOINTを使用する例についての話は省略します。
https://docs.docker.jp/engine/reference/builder.html#cmd
今回の例だと、以下がShell形式
CMD /usr/sbin/php-fpm7.4 -F -y /etc/php/7.4/fpm/php-fpm.conf
以下がExec形式となります。
CMD ["/usr/sbin/php-fpm7.4","-F","-y","/etc/php/7.4/fpm/php-fpm.conf"]
Shell形式は内部で /bin/sh -c
を使用しています。
そのため、実際に起動するコマンドはこうなります。
/bin/sh -c "/usr/sbin/php-fpm7.4 -F -y /etc/php/7.4/fpm/php-fpm.conf"
docker kill, Ctrl-CはPID1のプロセスにシグナルを送ります。 そのため、ここで受け取るプロセスは/bin/shになります。
Ubuntuのイメージを使用していた
Ubuntuの /bin/sh
は dash
を参照しています。
root@0bc44db82ffa:/# ls -la /bin/sh lrwxrwxrwx 1 root root 4 Jul 18 2019 /bin/sh -> dash
そのため、docker killやCtrl-Cはdashに送られます。 このことからわかるように、シェルは子プロセスにシグナル伝搬しないので、PHP-FPMまでシグナルが届かず今回のようにコンテナが終了しないということになります。
なぜCentOSなら終了するのか??
CentOSの /bin/sh
は bash
を参照しています。
[root@af2a4533ad51 /]# ls -la /bin/sh lrwxrwxrwx 1 root root 4 Nov 13 2020 /bin/sh -> bash
bashは-cで起動したプロセスにPIDが置き換わります。 今回のケースではPID1になるため、シグナルを受け取ることができコンテナを終了することができていたようでした。
まとめ
CMDで指定するコマンドは推奨されているExec形式を使っていこうず https://docs.docker.jp/engine/reference/builder.html#cmd
参考
https://www.creationline.com/lab/39662 https://qiita.com/ukinau/items/410f56b6d777ad1e4e90