このブログもDockerでコンテナ化してメンテナンスやバックアップを容易にしようと最近Dockerの勉強を始め、まずはWordPressの仮環境をDocker上で構築してみることにしました。
WordPressをDockerで構築する方法として、Docker Hubから入手できるWordPressとMySQLの公式イメージを使ってコンテナを作るというのがまず1つ挙げられるのですが、これだとWebサーバーがApacheの構成になってしまいます。
今までWebサーバーにはnginxを使ってきたので、Dockerでもnginxを使ってWordPressを動かしたいところです。
そこで、nginxの公式イメージと、Apacheの代わりにphp-fpmが付属しているWordPressの公式イメージ、それと先程もあげたMySQLの公式イメージを組み合わせてnginx + WordPress(php-fpm) + MySQLという構成の環境を組むことにしました。
今回のように複数コンテナを組み合わせて使う場合、本来ならばdocker-composeを使って環境構築すべきなのですが、Dockerの基礎から勉強したかったので今回はコマンドを1つずつ実行して気合で環境構築することにしました。
しかし、nginxのドキュメントに書かれている静的ファイルの置き場所が/usr/share/nginx/html
、それに対しWordPressのドキュメントに書かれている静的ファイルの置き場所が/var/www/html
となっているがために今回結構ハマってしまったので、その対応も合わせて述べていきます。
(nginxのコンテナの/var/www/html
に静的ファイルを置き、WordPressとパスを統一していれば今回のようにハマることは無かったのですが、まずはドキュメント準拠で環境構築したかったのであえてパスは統一していません。)
ちなみに、自分は大阪コード学園というYouTubeチャンネルにアップロードされているDocker入門講座を観て基礎の基礎を学習しました。ですので、下で記載しているDockerコマンドの記法もこの方のスタイルを踏襲したものとなっています。
環境構築手順
とりあえず下に続く手順を実行していけば、今回の目標であるnginx + WordPress(php-fpm) + MySQLの構成が完成します。
$
の左側はコマンドを実行している場所(コンテナ)を書いています。HostはホストPCです。
Network / Volumeの作成
Host $ docker network create mynetwork
Host $ docker volume create myvolume
Host $ docker volume create db
MySQLの準備
Host $ docker run --name mysql -dit --net mynetwork -v db:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=rootpass -e MYSQL_DATABASE=mydatabase -e MYSQL_USER=hoge -e MYSQL_PASSWORD=piyo mysql:5.7
nginxの準備
Host $ docker run --name nginx -dit --net mynetwork -v myvolume:/usr/share/nginx/html -p 8080:80 nginx
WordPressの準備
Host $ docker run --name wordpress -dit --net mynetwork -v myvolume:/var/www/html -e WORDPRESS_DB_HOST=mysql -e WORDPRESS_DB_USER=hoge -e WORDPRESS_DB_PASSWORD=piyo -e WORDPRESS_DB_NAME=mydatabase wordpress:php8.0-fpm
nginxによって生成される静的ファイル(Welcomeページ等)を消しておく
Host $ docker exec -it nginx bash
nginx $ rm /usr/share/nginx/html/index.html /usr/share/nginx/html/50x.html
nginxコンテナの/etc/nginx/conf.d/default.confを以下のように書き換える
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.php;
client_max_body_size 32M;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
設定を読ませる
nginx $ service nginx reload
動作確認
これでホストPCからlocalhost:8080
にアクセスするとWordPressの初期設定画面が表示されるはずです。
ハマった箇所
記事冒頭でも、今回nginxとWordPressでファイルの置き場所が違うのでハマったという話をしました。
現象としては、nginxのコンテナからlsを使っても普通にwp-adminなどのWordPressのファイル群は見えるし、default.confでもベースディレクトリーに正しいパスが指定されているのにも関わらず、localhost:8080にアクセスすると「File not found.」と返ってくるというものでした。
徹夜で原因究明していて頭もろくに回っていなかったので、寝て起きてから再度原因究明にあたっていたのですが、その時1つの気付きを得ました。
それは404の表示がnginxのものではないということです。
調べてみるとこれはphp-fpmの404表示のようでした。
ということは、「nginxからphp-fpmへのリレーができていないのでは」という仮説が立ちます。
そこで調べてみるとstackoverflowのとあるスレッドに辿り着きました。
どうやら、default.confで定義しているfastcgi_paramのSCRIPT_FILENAME
の値が間違っているようです。
というのも、一般的なWordPress用の設定ではSCRIPT_FILENAME
の値として$document_root$fastcgi_script_name
を指定します。
# 省略
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# 省略
実際にファイルに書く時はこんな感じです。
自分も最初はこれになぞらえて設定していました。
しかし、$document_rootと$fastcgi_script_nameの中身をログ出力させてみると
$document_root | $fastcgi_script_name |
/usr/share/nginx/html | /アクセスされたphpファイル |
となっていることがわかりました。
php-fpmはnginxのコンテナではなく、WordPressのコンテナ側で動いていますので、PHPを実行するにはWordPress側のコンテナのパスを与えなくてはいけません。しかし、$document_rootに代入されているパスはWordPress側のコンテナには存在しないので、ここでうまくリレーができなくなっていました。
そこで、$document_rootを使うのをやめ、/var/www/htmlというパスをハードコーディングすることによって、例えばlocalhost:8080/index.php
を見に行った場合、SCRIPT_FILENAME
に/var/www/html/index.php
という値が渡され、php-fpmがあるWordPress側のコンテナでもパスが通り、PHPが実行され、「File not found.」エラーも表示されなくなりました。
〆
やはり1つ1つコマンドを手打ちして動作を確認していくと勉強になります。と言っても今回はDockerというよりかはnginxの勉強になりましたが!
コメント