PHP-FPMのDockerfileのENTRYPOINTやCMDを上書きしたらエラーが起きた
課題
公式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"
環境
-
webサーバー
nginx 1.21.5
ベースイメージは、nginxの公式docker imageを使っています。 -
phpサーバー
8.1.1-fpm-bullseyes
ベースイメージは、phpの公式docker imageを使っています。
原因
ベースイメージのPHP-FPMのDockerfileのENTRYPOINTやCMDを上書きしたことが原因です。
則ち、下記のようなコードを書いたことが原因です。
FROM php:8.1-fpm
中略
COPY ./entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
ENTRYPOINTはコンテナ起動時に実行されるコマンドであり、CMDはそのコマンドの引数です。
ENTRYPOINTやCMDを上書きしてしまえば、元々のコマンドが実行されなくなってしまいます。
元々のコマンドの中には、PHP-FPMコンテナをPHPサーバーたらしめる処理が入っていました。
この処理を上書きしてしまっていたのです。
従って、PHP-FPMコンテナがPHPサーバーとしての役割を果たしていなかったのです。
原因の詳しい説明
ソースコードに基づいて詳しく説明していきます。
コードの意味については、コメントとしてコード内に書き込みました。
ベースイメージのDockerfileを読んでみましょう。
元々は下記のようにENTRYPOINTとCMDを指定しています。
# コンテナ起動時のコマンド
ENTRYPOINT ["docker-php-entrypoint"]
中略
# コンテナ起動時のコマンドの引数
CMD ["php-fpm"]
また、ベースイメージのENTRYPOINTで実行しているスクリプトを見てみましょう。
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で上書きするファイルの最後の一行に、下記を加えることで解決します。
php-fpm
この解決策の利点は、この問題を把握している人にとって単純明快なコードであることです。
欠点は、この問題を知らない人がコードが書かれた理由を分からないことです。このコードの真意を知るためには、この記事に書かれていることを把握する必要があります。
解決策2
元々のスクリプト自体を、ENTRYPOINTで上書きするファイルで読み込むことです。
則ち、docker-php-entrypointに引数php-fpmを与えて実行することです。
今回のケースだと、ENTRYPOINTで上書きするファイルの最後の一行に、下記を加えることで解決します。
. /usr/local/bin/docker-php-entrypoint php-fpm
この解決策の利点は、この問題を把握していない人にもコードが書かれた理由を示唆することです。
欠点は、処理が少し複雑になることです。
私はこちらの解決策の方が良いのかなと思います。
より汎用的な解決策でもあります。
最後に
DockerfileでENTRYPOINTやCMDを上書きする際は、元々のベースイメージでどんな処理を行っていたのか知るべきだと思いました。
また、ほぼ同じ内容の記事を偉大な先人が書いてくれていました。
折角自分なりに調べてみたので私も記事を書いてみましたが、偉大な先人の記事も是非読んでみて下さい。
Discussion