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

# アウトライン
1. 完成後の構築後イメージ
2. 構築
    1. ディレクトリ構成
    2. nginx
    3. php-fpm + CakePHP
    4. MySQL
3. 躓いたポイント

# 完成後の構築イメージ

<div align="center">
<img src=https://qiita-image-store.s3.amazonaws.com/0/190055/1b32b6ef-4fc6-c5f0-03f3-f4a9c41751d0.png "docker.png">
</div>

白抜きの四角は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

```yaml:docker-compose.yml
  nginx:
    build: ./nginx/
    ports:
      - 8080:80
    links:
      - phpfpm
    volumes:
      - ./data:/var/www/html
```

```dockerfile:Dockerfile
FROM nginx:1.15.5-alpine
COPY ./default.conf /etc/nginx/conf.d/default.conf
```

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

```nginx: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

```yaml:docker-compose.yml
  phpfpm:
    build: ./phpfpm/
    links:
      - mysql
    volumes:
      - ./data:/var/www/html
```

```dockerfile: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プロジェクトを作成する。

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

## MySQL

```yaml: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`にアクセス
<img width="2044" alt="スクリーンショット 2018-10-08 21.21.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/190055/a94bd277-1ac1-2a0b-7492-0b430836a730.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のリソースを両方のコンテナからアクセスできるようにした。