CakePHP4 を docker-compose で動くようにする

CakePHP4 もリリースされて時間が立ちました。
そろそろどんなものか触っていこうと思います。

でも、そのためには動かさないといけないので、まずは動かすところまでやってみます。


# この記事でわかること

- CakePHP4を nginx・php-fpm・MySQL で Mac(ローカルPC)上で動かせるようになります。
- この記事内のソースは以下で公開しています。
    - https://github.com/katsuhiko/cakephp-vue-study


# 事前準備

- Docker Desktop のインストール
    - https://www.docker.com/products/docker-desktop

僕の Mac に入っている Dockerの各種バージョンは以下です。

|  | バージョン |
|:-----------------|:------------------|
| docker           | Docker version 19.03.5, build 633a0ea |
| docker-compose   | docker-compose version 1.25.4, build 8d51620a |
| CakePHP4         | 4.0.4 |


# CakePHP プロジェクトの作成

ローカル環境に依存したくないで docker を使って CakePHP のプロジェクトも作ります。

CakePHP4 のプロジェクトを作るディレクトリに入れて、一時的なコンテナを立ち上げて入ります。
一時的なコンテナが独自なのは、最低限必要なライブラリを入れているためです。
( https://github.com/katsuhiko/docker-php-fpm-base/blob/master/Dockerfile )

php:7.4-fpm-buster で立ち上げて自身でライブラリ(zip, intlが最低限必要なライブラリかな！？)をインストールしてもOKです。

※ Windows の場合、試してないですが PowerShell を使えば動くと思います（そのために "" で囲んでるんで）。動かない場合、 ` $(pwd) ` の箇所を ` ${pwd} ` にすると良いのでないかなっと思います。たぶん。

```sh
cd .
docker run --rm -it -v "$(pwd):/home/app" -w /home/app katsuhikonagashima/php-fpm-base:7.4-buster /bin/bash
```

ここからはコンテナ内での作業になります。

composer を取得して、CakePHP4プロジェクトを作ります。
curl はすでに入っているはずです。
composer.phar は開発中に使うことになるので、作成したプロジェクトにコピーして含めるようにしています。

```sh

curl -sS https://getcomposer.org/installer | php

php composer.phar create-project --prefer-dist cakephp/app:4.* cakephp-vue-study

cp composer.phar ./cakephp-vue-study/
exit
```

ここからはコンテナから出て、ホスト側で作成したプロジェクト内での作業になります。
まずは、プロジェクトのディレクトリへ移動します。

```sh

cd ./cakephp-vue-study/
```

# docker-compose の準備

どこで docker 系のファイルを準備するかですが、僕は ` ./docker/local/ ` 配下に置くのが好きです。
本番へデプロイするファイルとわけることが多いので ` local ` というワンクッションをおいてます。
本当は本番・ローカルでファイルを別けたくないんだけど、ややこしくなっちゃうんですよね。。。この点は勉強中です。


## php-fpm の準備

` ./docker/local/php-fpm/Dockerfile ` を作成します。

zip, mysql, intl, gd を入れています。開発によって追加するライブラリがあると思うので、 php-fpm は Dockerfile を作ります。
buster(Debian) にしているのは、 apt を使うことに慣れているからだけです。ライブラリを追加するときに手間取りたくないからね。

```dockerfile:docker/local/php-fpm/Dockerfile

FROM php:7.4-fpm-buster

RUN apt-get update

RUN apt-get install -y git libzip-dev zip unzip \
    && docker-php-ext-install zip

RUN docker-php-ext-install pdo_mysql

RUN apt-get install -y libicu-dev \
    && docker-php-ext-configure intl \
    && docker-php-ext-install intl

RUN apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng-dev \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install gd
```


## nginx の準備

` ./docker/local/nginx/default.conf ` を作成します。

Cookbook ( https://book.cakephp.org/4/en/installation.html#nginx )の内容そのままに近いです。
` fastcgi_pass ` のところの ` app ` は php-fpm コンテナのサービス名です。後ほど docker-compose.yml で指定します。

```nginx:docker/local/nginx/default.conf

server {
    listen 80;
    listen [::]:80;
    server_name _;
 
    root  /var/www/html/webroot;
    index index.php;
 
    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;
 
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }
 
    location ~ \.php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        fastcgi_intercept_errors on;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}
```


## MySQL の準備

` ./docker/local/mysql/etc-mysql.cnf ` を作成します。

マルチバイトの対応をしているのみです。昨今絵文字（🍺とか）も保存したいですからね。

```:docker/local/mysql/etc-mysql.cnf
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci

[client]
default-character-set=utf8mb4
```

テスト用のデータベースを作るために初回実行時に流す SQL を ` ./docker/local/mysql/init/01_create_db.sql ` を準備します。

```sql:docker/local/mysql/init/01_create_db.sql
CREATE DATABASE app_test;
```


## docker-compose.yml の作成

` ./docker-compose.yml ` を作成します。

` networks ` の設定は趣味みたいな感じです。複数のアプリケーションでDBを共有したいっというときには役立つんですが、現時点では不要ですね。

` container_name ` を指定すると ` docker exec ` 等でのコンテナ名指定が固定化されるので好んで指定しています。

php-fpm を ` app ` としている点が先程の ` ./docker/local/nginx/default.conf `  の記述に関連しているところです。
nginx は、追加でライブラリを入れることはないのでコンテナサイズ重視で alpine にしています。 
mysql が 5.7 なのは、実業務では AWS Aurora を使うことが多いためです。

```yaml:docker-compose.yml

version: '3.5'

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

volumes:
  db-data:
    driver: local

services:
  web:
    image: nginx:1.16-alpine
    container_name: web
    ports:
      - 80:80
    volumes:
      - ./docker/local/nginx/default.conf:/etc/nginx/conf.d/default.conf
      - ./:/var/www/html
    networks:
      - frontend
      - backend
  app:
    build: ./docker/local/php-fpm
    container_name: app
    volumes:
      - ./:/var/www/html
    networks:
      - backend
  db:
    image: mysql:5.7
    container_name: db
    ports:
      - 3306:3306
    environment:
      - MYSQL_DATABASE=app_default
      - MYSQL_USER=default
      - MYSQL_PASSWORD=secret
      - MYSQL_ROOT_PASSWORD=root
    volumes:
      - ./docker/local/mysql/etc-mysql.cnf:/etc/mysql/conf.d/etc-mysql.cnf
      - ./docker/local/mysql/init:/docker-entrypoint-initdb.d
      - db-data:/var/lib/mysql
    networks:
      - backend
```


## DB 接続設定

` ./config/app_local.php ` のDB接続情報を変更します。
host, username, detabase の箇所を変更しています。
host にしている ` db ` は mysql コンテナのサービス名です。docker-compose.yml で記載しています。

また、 DB のユーザーで悩みたくないので root へ変更しています。

` ./config/app_local.php ` はソース管理のリポジトリには含めないファイルになるので ` ./config/app_local.example.php ` にも同じ変更を反映しておきましょう。

```php:config/app_local.php
    'Datasources' => [
        'default' => [
            'host' => 'db',
            'username' => 'root',
            'password' => 'root',
            'database' => 'app_default',
            'url' => env('DATABASE_URL', null),
        ],

        'test' => [
            'host' => 'db',
            'username' => 'root',
            'password' => 'root',
            'database' => 'app_test',
        ],
    ],
```


# docker-compose の実行

初回の起動は時間がかかりますが、2回目からの起動からはイメージがキャッシュされるので速いです。

```sh
docker-compose up -d
```


# 動作確認

http://localhost へアクセスするといつもの CakePHP のトップページが表示されます。

Database のところがきちんと緑色になって接続できていることを確認してください。
これで開発の準備ができました。


# 補足） Github へアップする

```sh
git init
git add --all
git commit -m "create cakephp4 project."
git remote add origin https://github.com/katsuhiko/cakephp-vue-study.git
git push -u origin master
```


# 補足)  別のローカル環境で始めるとき

先にコンテナを起動してから、composer install してライブラリを取り込むのがポイントです。
コンテナ名を app 指定にしたから、 ` docker exec ` するときスッキリしてるんじゃないかなっと思います。

```sh
git clone https://github.com/katsuhiko/cakephp-vue-study.git
cd ./cakephp-vue-study

cp ./config/.env.example ./config/.env
cp ./config/app_local.example.php ./config/app_local.php

docker-compose up -d
docker exec -it app php composer.phar install
```