📦

PHP-FPMのDockerfileのENTRYPOINTやCMDを上書きしたらエラーが起きた

2021/12/31に公開

課題

公式php-fpmをベースイメージにしてDockerfileでENTRYPOINTを上書きしたら、nginxの502エラーで接続出来なくなった。

nginxのコンテナのエラーログは下記の通り

2021/12/30 06:40:06 [error] 24#24: *8 connect() failed (111: Connection refused) while connecting to upstream, client: xxx.xxx.xxx.xxx, server: , request: "GET /favicon.ico HTTP/1.1", upstream: "fastcgi://xxx.xxx.xxx.xxx:xxx", host: "xxx.xxx.xxx.xxx", referrer: "xxx.xxx.xxx.xxx"

環境

原因

ベースイメージのPHP-FPMのDockerfileのENTRYPOINTやCMDを上書きしたことが原因です。
則ち、下記のようなコードを書いたことが原因です。

Dockerfile
FROM php:8.1-fpm
中略
COPY ./entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]

ENTRYPOINTはコンテナ起動時に実行されるコマンドであり、CMDはそのコマンドの引数です。
ENTRYPOINTやCMDを上書きしてしまえば、元々のコマンドが実行されなくなってしまいます。
元々のコマンドの中には、PHP-FPMコンテナをPHPサーバーたらしめる処理が入っていました。
この処理を上書きしてしまっていたのです。
従って、PHP-FPMコンテナがPHPサーバーとしての役割を果たしていなかったのです。

原因の詳しい説明

ソースコードに基づいて詳しく説明していきます。
コードの意味については、コメントとしてコード内に書き込みました。

ベースイメージのDockerfileを読んでみましょう。
元々は下記のようにENTRYPOINTとCMDを指定しています。

Dockerfile
# コンテナ起動時のコマンド
ENTRYPOINT ["docker-php-entrypoint"]
中略
# コンテナ起動時のコマンドの引数
CMD ["php-fpm"]

また、ベースイメージのENTRYPOINTで実行しているスクリプトを見てみましょう。
ENTRYPOINTで実行しているスクリプトは以下の通りです。

docker-php-entrypoint
#!/bin/sh

# エラーが起きたらスクリプトを強制終了する。
set -e

# デフォルトの引数はCMDで指定している『php-fpm』のみ
# 1番目の引数が『-』から始まる場合(1番目の引数が-fとか-eとかである場合)
if [ "${1#-}" != "$1" ]; then
	# 1番目の引数に『php-fpm』を加える
	set -- php-fpm "$@"
fi

# 全ての引数を実行する
exec "$@"

要するに、元々のスクリプトはコマンド『php-fpm』を実行するスクリプトです。
ENTRYPOINTやCMDを上書きする際に、コマンド『php-fpm』を実行する処理を含まないと、表題のようなエラーが出るのです。

解決策

元々の処理が実行されるようにすれば解決します。
すなわち、コマンド『php-fpm』を実行すれば解決します。

私は2つの解決策を提示します。

解決策1

元々のスクリプトと同様な処理を、ENTRYPOINTで上書きするファイルに書くことです。
則ち、コマンド『php-fpm』を実行することです。

今回のケースだと、ENTRYPOINTで上書きするファイルの最後の一行に、下記を加えることで解決します。

entrypoint.sh
php-fpm

この解決策の利点は、この問題を把握している人にとって単純明快なコードであることです。
欠点は、この問題を知らない人がコードが書かれた理由を分からないことです。このコードの真意を知るためには、この記事に書かれていることを把握する必要があります。

解決策2

元々のスクリプト自体を、ENTRYPOINTで上書きするファイルで読み込むことです。
則ち、docker-php-entrypointに引数php-fpmを与えて実行することです。

今回のケースだと、ENTRYPOINTで上書きするファイルの最後の一行に、下記を加えることで解決します。

entrypoint.sh
. /usr/local/bin/docker-php-entrypoint php-fpm

この解決策の利点は、この問題を把握していない人にもコードが書かれた理由を示唆することです。
欠点は、処理が少し複雑になることです。

私はこちらの解決策の方が良いのかなと思います。
より汎用的な解決策でもあります。

最後に

DockerfileでENTRYPOINTやCMDを上書きする際は、元々のベースイメージでどんな処理を行っていたのか知るべきだと思いました。

また、ほぼ同じ内容の記事を偉大な先人が書いてくれていました。
折角自分なりに調べてみたので私も記事を書いてみましたが、偉大な先人の記事も是非読んでみて下さい。

https://qiita.com/shim-hiko/items/653059fab63af962a21f

Discussion