docker でフロントとバックの web サーバーを分け php（Laravel） nginx mysql の開発環境を構築する

#はじめに
docker で php（Laravel） nginx mysql の開発環境を作成した折、
フロントエンド、バックエンドを web サーバーごと分ける構成にしたので一例として見ていただけたらと思います。
なお接続するデータベース（mysql）は同一です。

mysql コンテナ起動時にデータベースとユーザまで作成しておきたかったので、
コンテナの /docker-entrypoint-initdb.d 配下に .sql ファイルをボリュームしています。
また、マイグレーション用とプロジェクト用でユーザは分けています。

筆者は docker 使用歴1ヵ月ほどで、
docker-compose.yml や Vagrantfile を自身で作成するのは初めてなので、
修正案等どしどし送っていただけたら幸いです。

#環境
使用PCが windows 10 home で docker for windows は使えないため、
docker toolbox での開発環境作成となります。



#docker側

###ディレクトリ構成
```
.
├─ docker-compose.yml
├─ mysql
│       └─data
│       └─sql
│       │    └─initdb.sql
│       │    └─inituser.sql
│       └─.env
├─ nginx_front
│       └─default.conf
├─ nginx_back
│       └─default.conf
├─ php_front
│       └─Dockerfile
├─ php_back
│       └─Dockerfile
└─ backend_app（Laravel プロジェクト）
└─ frontend_app（Laravel プロジェクト）
```
###docker-compose.yml
```yml
version: '3'
services:
  nginx_front:
    image: nginx:1.13.9-alpine
    ports:
      - "8080:80" // front と back でポート分け
    depends_on:
      - php_front
    volumes:
      - ./nginx_front/default.conf:/etc/nginx/conf.d/default.conf
      - ./frontend_app:/var/www/laravel

  php_front:
    build: ./php_front
    env_file: ./mysql/.env
    depends_on:
      - mysql
    volumes:
      - ./frontend_app:/var/www/laravel

  nginx_back:
    image: nginx:1.13.9-alpine
    ports:
      - "80:80"　// front と back でポート分け
    depends_on:
      - php_back
    volumes:
      - ./nginx_back/default.conf:/etc/nginx/conf.d/default.conf
      - ./backend_app:/var/www/laravel

  php_back:
    build: ./php_back
    env_file: ./mysql/.env
    depends_on:
      - mysql
    volumes:
      - ./backend_app:/var/www/laravel

  mysql:
    image: mysql:5.7.21
    env_file: ./mysql/.env
    ports:
      - "3306:3306"
    command: --innodb-use-native-aio=0
    volumes:
      - ./mysql/sql:/docker-entrypoint-initdb.d　// イニシャルで実行する .sql ファイルを配置
      - ./mysql/data:/var/lib/mysql　// トップレベルボリュームを使用するか迷いましたが今回はフォルダ指定
```
###Dockerfile（front, back共に同じ内容）
```dockerfile
FROM php:7.2.2-fpm-alpine3.6

ENV COMPOSER_ALLOW_SUPERUSER 1　// rootでの composer install を許可

RUN docker-php-ext-install pdo_mysql mysqli mbstring && \
    curl -sS https://getcomposer.org/installer | php && \
    mv composer.phar /usr/local/bin/composer

WORKDIR /var/www/laravel
```
###default.conf（front）
```conf
server {
    listen 80;
    server_name _;

    root   /var/www/laravel/public;
    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$ {
        fastcgi_split_path_info ^(.+\.php)(\.+)$;
        fastcgi_pass php_front:9000;　// コンテナのタグを設定
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}
```
###default.conf（back）
```
server {
    listen 80;
    server_name _;

    root   /var/www/laravel/public;
    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$ {
        fastcgi_split_path_info ^(.+\.php)(\.+)$;
        fastcgi_pass php_back:9000;　// コンテナのタグを設定
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}
```
###inituser.sql
```sql
-- ユーザー作成
create user `client_user`@`%` identified by 'client_user';
create user `admin_user`@`%` identified by 'admin_user';
create user `builder`@`%` identified by 'builder';

/*
webアプリ用ユーザー
client_user, admin_user
*/
GRANT select,update,insert,delete ON `db_name`.* TO `client_user`@`%`;
GRANT select,update,insert,delete ON `db_name`.* TO `admin_user`@`%`;

/*
migration用ユーザー
builder
*/
GRANT create,drop,alter,index,select,update,insert,delete ON `db_name`.* TO `builder`@`%`;
```
###initdb.sql
```sql
create database db_name;
```
###.env
```
DB_CONNECTION=mysql
DB_HOST=mysql // Docker toolbox だと 127.0.0.1 では上手くいかず、docker-compose.yml でのコンテナ名指定で接続できた
DB_PORT=3306
DB_DATABASE=db_name
MYSQL_ROOT_PASSWORD=password // MYSQL_ROOT_PASSWORD 環境変数は設定必須（空欄不可）
```

#Laravel プロジェクト側

###.env
```
APP_NAME=Laravel
APP_ENV=local
APP_KEY=　// コンテナを立ち上げ時に php artisan key:generate する
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=DB_HOST // docker-compose up 時に読み込まれる .env の環境変数を読み込む。 "mysql"でもOK
DB_PORT=3306

DB_DATABASE_SERVICE=db_name

// backend_app のみ
DB_USERNAME_SERVICE=admin_user
DB_PASSWORD_SERVICE=admin_user
DB_USERNAME_MIGRATE=builder
DB_PASSWORD_MIGRATE=builder

// frontend_app のみ
DB_USERNAME_SERVICE=client_user
DB_PASSWORD_SERVICE=client_user

BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
```
###database.php
```php
'mysql' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE_SERVICE', 'forge'),
            'username' => env('DB_USERNAME_SERVICE', 'forge'),
            'password' => env('DB_PASSWORD_SERVICE', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => true,
            'engine' => null,
        ],

// backend_app のみ
'mysql_migrate' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE_SERVICE', 'forge'),
            'username' => env('DB_USERNAME_MIGRATE', 'forge'),
            'password' => env('DB_PASSWORD_MIGRATE', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => false,
            'engine' => null,
        ],
```
#コンテナ立ち上げ

※docker toolbox で実行する場合 `docker-compose up -d` の前に下記を実行

```
$Env:COMPOSE_CONVERT_WINDOWS_PATHS = "true"
```
####①イメージのビルド&コンテナ立ち上げ
```
docker-compose up -d
```
####②コンテナIDの確認
```
docker ps -a
```
####③フロントエンドアプリのコンテナに入って作業
```
docker exec -it [php_frontのコンテナID] /bin/sh　// コンテナに入る
composer create-project --prefer-dist laravel/laravel .　//  フロントエンドアプリのLaravelプロジェクト作成　※プロジェクト作成後 .env と database.php を修正
php artisan key:generate　// APP_KEY作成
exit　// コンテナを出る
```
####④バックエンドアプリのコンテナに入って作業
```
docker exec -it [php_backのコンテナID] /bin/sh　// コンテナに入る
composer create-project --prefer-dist laravel/laravel .　//  バックエンドアプリのLaravelプロジェクト作成　※プロジェクト作成後 .env と database.php を修正
php artisan key:generate　// APP_KEY作成
php artisan migrate --database=mysql_migrate　// migrate 用ユーザである builder にのみ create 権限を付与しているため、接続先を指定して migrate
exit　// コンテナを出る
```
####⑤ブラウザにアクセス
※docker toolbox の場合 localhost ではなく、
`docker-machine ip`で docker toolbox の ipを確認し、その IP アドレスにアクセスする
`http://[docker-machine ip]:8080`　フロントエンドアプリにアクセス
`http://[docker-machine ip]:80`       バックエンドアプリにアクセス