phpLDAPadminを使いたいことがあって、Docker ComposeでNginxとPHPを立ち上げて、そこで動かしました。
今度また、WebでPHPを使いたくなった時用に、Docker ComposeでPHPが動くNginxを用意するための、自分用テンプレートメモです。
せっかくなので後々使い勝手がいいよう、MySQLも加えた、LEMP環境にしました。
…と言っても、大したことはしてなくて、Webサーバーとして、NginxとPHPの両方をインストールしたコンテナを作成しているだけなんですけどね。
構成
- Web
- NginxとPHPが稼働
- 動作テスト用に「phpinfo()」と「phpMyAdmin」をインストール
- MySQL
- volumeでデータは外部に保存
テンプレート
docker-compose.yaml
- WebサーバーはDockerfileを使って、自分でイメージを作ります
- MySQLは公式からイメージを持ってきてます。バージョンは8です(後々このバージョンが原因でハマることになりましたが…)
version: "3" services: web: build: "./web" ports: - 80:80 mysql: image: mysql command: --default-authentication-plugin=mysql_native_password volumes: - mysql-data:/var/lib/mysql environment: MYSQL_ROOT_PASSOWRD: rootpassword # phpmyadmin: # image: phpmyadmin/phpmyadmin # environment: # PMA_HOST: mysql # ports: # - 8080:80 volumes: mysql-data:
Dockerfile
WebサーバーのDockerfile。「./web/」に置きます。
FROM php:fpm RUN apt-get update # install php extension RUN docker-php-ext-install mysqli && \ docker-php-ext-enable mysqli # install Nginx RUN apt-get -y install nginx COPY default /etc/nginx/sites-enabled/default # test contents COPY phpinfo.php /var/www/html/phpinfo.php COPY phpMyAdmin/ /var/www/html/phpMyAdmin/ # run Nginx & PHP COPY start.sh /start.sh RUN chmod 744 /start.sh EXPOSE 80 CMD ["/start.sh"]
default
Nginxの設定ファイルを修正して、PHPが実行されるようにします。
... location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass localhost:9000; } ...
start.sh
Webサーバーで実行されるスクリプト。PHPとNginxを起動しています。
#!/bin/bash
nginx
php-fpm
動作テスト
http://localhost
http://localhost/phpinfo.php
http://localhost/phpMyAdmin/index.php
補足説明
Web:Nginx+PHP
NginxとPHPを同じコンテナで動かしたかったので、Dockerfileを使ってイメージを作成しています。
どちらをベースにしてもいいのですが、ここでは、PHPのイメージをベースに、Nginxをインストールしています。
NginxとPHPを同時に動かすため、それらを呼び出すスクリプト「start.sh」を作成し、CMDで呼び出しています。
コマンドnginx
はバックグラウンドで実行され、コマンドphp-fpm
はフォアグラウンドで実行されるので「nginx->php-fpm」の順で実行すると、Nginx・PHPが両方動いた状態で「start.sh」プロセスが永続します。
実行順を逆にしたい場合は、php-fpm
をバックグラウンドで実行し、NginxのDockerfileのようにdeamon off
オプションを使って、フォアグラウンドでnginx
を実行させます。
#!/bin/bash php-fpm & nginx -g deamon off
PHP拡張モジュール
PHP拡張モジュールを、DockerのPHPイメージでインストールするには
RUN apt-get install php-xxx
とはせず
RUN docker-php-ext-install xxx
と、専用コマンドを使います。
RUN docker-php-ext-install <extension_name>
でインストールし、RUN docker-php-ext-enable <extension_name>
で利用可能にします。
インストールにあたり、依存関係のライブラリがあっても、ライブラリのインストールは自動ではしてくれないので、自分で関係ライブラリをインストールしてから、PHP拡張モジュールをインストールする必要があります。
例えば「phpLDAPadmin」は「php-ldap」「php-xml」「php-gettext」のPHP拡張モジュールを使うのですが、それらのPHP拡張モジュールは「libldap2-dev」「libxml2-dev」を必要とするので、下記のような記述をDockerfileに記載してインストールする必要がありました。
# install php-ldap RUN apt-get install libldap2-dev -y && \ docker-php-ext-install ldap && \ docker-php-ext-enable ldap # install php-xml RUN apt-get install libxml2-dev -y && \ docker-php-ext-install xml && \ docker-php-ext-enable xml # install php-gettext RUN docker-php-ext-install gettext && \ docker-php-ext-enable gettext
MySQL
MySQLのバージョン8から、デフォルトの認証プラグインが、バージョン5以前の「mysql_native_password」から「caching_sha2_password」に変更になっています。
PHPのMySQLライブラリはまだ「caching_sha2_password」に対応しておらず、phpMyAdminでログインしようとすると、下記のようなエラーが出てしまいます。
The server requested authentication method unknown to the client
デフォルトの認証プラグインはmysqld
のオプションで変更できるので、「docker-compose.yaml」内の「command」で変更しています。
command: --default-authentication-plugin=mysql_native_password
ただし、オプションによるデフォルトの認証プラグインの設定は、MySQLの初回構築時のみ有効で、一度構築されると後からオプションを変更しても反映されません。
特にVolumeでデータを外部に保存するようにしていて、初回構築後に設定を変更すると、コンテナがエラーで終了するので注意が必要です。
認証プラグインの設定はユーザー毎に設定可能なので、デフォルトの認証プラグインの設定で対応せず、MySQLの初回構築が終わった後で、PHPでアクセスするユーザーの認証プラグインを「mysql_native_password」に変更して対応することもできます。(ここではその方法は割愛しました)
感想など
Nginx+PHP
本来、NginxとPHPのコンテナを分けるのが、Docker的な構成なんでしょうね。
ただ、コンテナを分けた場合、PHPファイルはNginx側ではなく、PHPコンテナ側に置く必要があります。 一方、PHPファイル以外のhtmlや画像ファイルはNginx側に置くので、phpMyAdminのように、PHP・HTML・画像などが1つのフォルダに入って配布されるアプリの場合、Nginx・PHP両方のコンテナにコピーを置く必要があります。
しかし、フォルダを一箇所にまるっと置いて終わりとしたいのが心情というもので、その場合、Volumeを使って、NginxコンテナとPHPコンテナでコンテンツフォルダを共有させたりします。
docker-compose.yaml だとこんな感じ。
version: "3" services: nginx: build: "./nginx" ports: - 80:80 volumes: - ./share/:/usr/share/nginx/html/ php: build: "./php" volumes: - ./share/:/var/www/html/
最初そのやり方で作ってみたのですが、今回はコンテンツをコンテナと切り離して永続化したかったわけではなく、むしろ、コンテンツをコンテナの中に固めてパッケージ化したかったので、結局1つのコンテナにNginx・PHP・コンテンツを詰め込むことにしました。
Volumeを使うと、何か問題が発生した時、同じ条件でやってるつもりでも、実はVolumeの中身は同じではなく、それに気づかずハマるということがあるので、コンテンツの置き場所を、Volumeにしたくなかったというのもあります。
phpMyAdmin
ここでは、PHPのサンプルとして「phpMyAdmin」をWebサーバー上で動かしてみましたが、phpMyAdminのイメージが配布されているので、それを直接使った方が楽です。 (参考までにDockerfileのコメントアウト部分に記載しましたので、コメントを外すとポート8080でphpMyAdminに直接アクセスできるようになります)
その他
おまけで追加したつもりの、MySQL関連で一番ハマりました…。
MySQLバージョン8で、WITH句、ウィンドウ関数が使えるようになったんですね!いいこと知りました!
参考記事
- https://dev.mysql.com/doc/refman/5.6/en/server-options.html#option_mysqld_default-authentication-plugin
- https://medium.com/@crmcmullen/how-to-run-mysql-8-0-with-native-password-authentication-502de5bac661
- https://stackoverflow.com/questions/52364415/php-with-mysql-8-0-error-the-server-requested-authentication-method-unknown-to
- https://qiita.com/ucan-lab/items/3ae911b7e13287a5b917
- https://www.s-style.co.jp/blog/2018/05/1807/
- https://employment.en-japan.com/engineerhub/entry/2018/09/18/110000
- https://qiita.com/bossunn24/items/85ca5c3bfbba07b4e0cc
- https://qiita.com/bzy/items/f251d47cba836a3a92df
- https://hub.docker.com/_/mysql
- https://hub.docker.com/_/php