Edited at

Dockerでnginx + php-fpm(CakePHP) + MySQL を立ち上げるまでの長い道のり


アウトライン


  1. 完成後の構築後イメージ

  2. 構築


    1. ディレクトリ構成

    2. nginx

    3. php-fpm + CakePHP

    4. MySQL



  3. 躓いたポイント


完成後の構築イメージ



白抜きの四角はdockerコンテナ。nginx, php-fpm, MySQLのコンテナを利用する。

青色の四角はホストOSのディレクトリ。

ポイント

nginxとphp-fpmがホストOSの同一ディレクトリをマウントする。


構築


ディレクトリ構成

ホストOS側からみた設定ファイル等のディレクトリ構成

.

├── data
├── docker-compose.yml
├── nginx
│   ├── Dockerfile
│   └── default.conf
└── phpfpm
└── Dockerfile

■dataディレクトリ

 nginxとphpが共通のドキュメントルートを利用するために利用。静的ファイルをnginxが返却できるように同一のデータを閲覧できるようにする。nginxが静的ファイルを返却する必要がないなら、全てのリクエストをphp-fpm側に流してしまえば良いため、同じ場所をマウントする必要はない。


nginx


docker-compose.yml

  nginx:

build: ./nginx/
ports:
- 8080:80
links:
- phpfpm
volumes:
- ./data:/var/www/html


Dockerfile

FROM nginx:1.15.5-alpine

COPY ./default.conf /etc/nginx/conf.d/default.conf

■volumes

ホストOSの./dataディレクトリをドキュメントルートの上位ディレクトリ/var/www/htmlへマウントする。(実際のドキュメントルートディレクトリは後ほどphp側で作成)


default.conf

server {

listen 80;
server_name _;
root /var/www/html/myapp/webroot;
index index.php

access_log /var/log/nginx/access_log;
error_log /var/log/nginx/error_log debug;

location / {
try_files $uri $uri/ /index.php$is_args$args;
}

location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(\.+)$;
fastcgi_pass phpfpm:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}


後の手順でmyappプロジェクトをCakePHPで作成する。CakePHPでは、myapp/webrootをルートにするよう指示している。

try_filesでは、左から順にそのリソースがあるか確認する。ない場合はCakePHPのindex.phpにリクエストする。静的コンテンツがあれば、nginxが静的コンテンツを返却する。

ポイントはfastcgi_passでphpfpm:9000を指定すること。linksのおかげでphpfpmをnginxコンテナ内で名前解決できる。(Hostsファイルとかに書いてくれてるのかな?)


php-fpm + CakePHP


docker-compose.yml

  phpfpm:

build: ./phpfpm/
links:
- mysql
volumes:
- ./data:/var/www/html


Dockerfile

FROM php:7.2.10-fpm-stretch

RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \
php -r "if (hash_file('SHA384', 'composer-setup.php') === '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" && \
php composer-setup.php && \
php -r "unlink('composer-setup.php');" && \
mv composer.phar /usr/local/bin/composer && \
apt-get update && \
apt-get install -y libicu-dev && \
docker-php-ext-install intl pdo_mysql mbstring && \
apt-get install -y git && \
apt-get install -y zip unzip && \
composer config -g repos.packagist composer https://packagist.jp && \
composer global require hirak/prestissimo

DockerfileではcomposerのセットアップとCakePHP用のライブラリ(intl, pdo_mysql)をインストールしている。composerが内部でgitやzip, unzipを利用しているようなのでインストールしておく。

Dockerfileの後半2行はcomposer高速化対応なので、削除しても問題ない。

コンテナ起動後、/var/www/html/にCakePHPプロジェクトを作成する。

composer create-project --prefer-dist cakephp/app myapp


MySQL


docker-compose.yml

  mysql:

image: mysql:8.0.12
environment:
MYSQL_DATABASE: my_app
MYSQL_USER: my_app
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: password

CakePHPのデフォルトのDB設定名に合わせて設定値を追加。MYSQL_ROOT_PASSWARDは不要か?


接続確認

ホストOSからlocalhost:8080にアクセス

スクリーンショット 2018-10-08 21.21.43.png


躓いたポイント


CakePHPプロジェクトのプロジェクトがコンテナ起動時に消去される

docker-composeでドキュメントルートをマウントすると、

1. コンテナ起動時に

2. ホストOSのディレクトリ構成をコンテナにマウント(上書き)する。

Dockerfileで作られたCakePHPのプロジェクトはマウント時に上書きされて無くなる。

対応策として、CakePHPのプロジェクトはコンテナ起動後に手動で作成した。

DockerfileのCMDを使えば、手動が不要になる気がする。


静的コンテンツが返却されない

nginxコンテナとphpコンテナでホストOSをマウントしていなかった。そのため、CakePHPのTOPページをアクセスしてもcssやpngのようなファイルが返却されなかった。理由は簡単で、nginx側コンテナにはcss, pngなどの静的ファイルが存在しないから。

言われてみれば当たり前だけど困った。

nginxコンテナからphpコンテナをマウントする方法も検討したけど、どのパスがどのパスとマウントされるかよく分からなかった。

対応策としてホストOSのディレクトリをマウントしてCakePHPのリソースを両方のコンテナからアクセスできるようにした。