schedule2020-10-04

Laravel + Nginx + MySQLのDocker開発環境を共有します

Laravel向けのDocker開発環境を整えたので共有します。

本番でもDockerが使えるように色々試しているとこですので、自分が把握できた範囲の構成です。

githubに置いときます。

目標とミドルウェアの構成

目標はDockerを立ち上げて直ぐにLaravelの開発ができるようにすること。composerとnodejsも一緒に用意します。

構成とバージョン。最新になるようにしています。

  • php (php-fpm) 7.4.1
    • composer 1.10.13
    • nodejs v12.18.4
    • npm 6.14.6
  • mysql 8.0 (5.7も可能)
    • パスワードなど初期設定をする。
  • nginx 1.19.2
    • Laravel向けのconfを用意する。

ホスト環境

今回の趣旨に関係ありませんが、ホストOSはWindows10です。

  • Windows 10 Home バージョン2004(OSビルド 19041.508)
  • WSL2 (Ubuntu 20.04.1 LTS)
  • Docker version 19.03.13, build 4484c46d9d
  • docker-compose version 1.27.4, build 40524192

WSL2が出てWindows HomeでもDockerが使えるようになりました。 インストール方法はMicrosoftの手順を解説したQiita @KoKeCrossの記事の通り進めて行けばOKです。

ディレクトリ構成

/project
├─ /docker    # コンテナ内のデータ保存先
|  ├─ /db
|  |  ├─ /data           # データベース保存先
|  |  ├─ /sql
|  |  └─ /my.conf        # mysqlの設定(今回は空ファイル)
|  ├─ /nginx
|  |  └─ /default.conf   # Nginxの設定
|  └─ /php
|     ├─ /Dockerfile     # phpコンテナの設定
|     └─ /php.ini        # phpの設定
├─ /web       # アプリケーションコード
└─ docker-compose.yml

docker-compose.yml

php, nginx, dbのコンテナを作ります。mysqlはdb。

version: '3'

volumes:
  vendor-store:
  node_modules-store:

services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
    - ./web:/var/www
    - vendor-store:/var/www/laravel/vendor
    - node_modules-store:/var/www/laravel/node_modules
    environment:
      TZ: Asia/Tokyo

  nginx:
    image: nginx
    container_name: nginx
    ports:
    - 80:80
    volumes:
    - ./web:/var/www
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
    - php

  db:
    image: mysql:8.0
    container_name: db
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
    - ./docker/db/data:/var/lib/mysql
    - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
    - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
    - 3306:3306

imageDocker-Hubにあるビルド済みイメージを指定している。 有名なミドルウェアは公式のものがあります。 phpコンテナはNodejsやcomposerをインストールするため、Dockerfileからビルドします。

volumesはホストとコンテナのディレクトリとファイルを同期する。 ホストの/webをphp・nginxコンテナのエントリーポイント/var/wwwに指定しました。 Laravelプロジェクトは/webにクローンするか、phpコンテナの/var/wwwで新規作成して開発が可能です。

vendorとnode_modulesは名前付きボリュームに格納して、ホスト側とコンテナ側と分離して管理している。 同期処理が発生しないため、その分速くなる。

dbのenvironmentに初期設定を渡せる。 これを.envに書いたり、ホストのSQLクライアントの接続にそのまま使えます。 その他の変数はdockerhub mysqlでご確認ください。

mysql:8.0mysql:5.7にしても動作確認とれた。

php/Dockerfile

FROM php:7.4.1-fpm

COPY php.ini /usr/local/etc/php/

RUN apt update
RUN apt install -y wget git unzip libpq-dev

# Install Node.js 12
RUN apt install -y npm \
  && npm install n -g \
  && n 12

# Install PHP Extensions
RUN apt install -y zlib1g-dev mariadb-client libzip-dev libonig-dev \
  && docker-php-ext-install zip pdo_mysql

# Install Composer
RUN curl -sS https://getcomposer.org/installer | php \
  && mv composer.phar /usr/local/bin/composer \
  && composer self-update

WORKDIR /var/www

# php-fpmはデフォルトのユーザwww-dataで動く。https://stackoverflow.com/questions/48619445/permission-denied-error-using-laravel-docker
# 変更する場合は /usr/local/etc/php-fpm.d/www.conf でユーザー名を変える。
RUN chown -R www-data:www-data /var/www

RUN composer global require "laravel/installer"

php:7.4.1-fpmのイメージにNode.jsやComposerをインストールしていくDockerfileです。

aptだとNodejsは古いため、パッケージマネージャのnで新しいバージョンをインストールしています。 以下のようにスクリプトでインストールする方法もあります。

# Install Node.js 12
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - \
 && apt install -y nodejs

php 7.4ではビルド時にonigumaが見つからないとエラーが出ます。 aptではlibonig-dev(library onigumaかな?)をインストールすると回避できる。 参考1,参考2

必要な拡張はdocker-php-ext-installに追加していく。

nginxはphp-fpmを通してLaravelを実行します。 /var/www以下のファイルにユーザwww-dataの実行権限を与えます。 www-dataはphp-fpmのデフォルトユーザです。 /usr/local/etc/php-fpm.d/www.confを修正してユーザ名を変更できます。

dockerhub php

/php/php.ini

[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

cliもfpmのphpもこの設定を参照します。

/nginx/default.conf

server {
  listen 80;
  // root /var/www/{Laravelプロジェクト名}/public;
  root /var/www/laravel/public;

  add_header X-Frame-Options "SAMEORIGIN";
  add_header X-XSS-Protection "1; mode=block";
  add_header X-Content-Type-Options "nosniff";

  index index.php;
  charset utf-8;

  location / {
    try_files $uri $uri/ /index.php?$query_string;
  }

  location = /favicon.ico { access_log off; log_not_found off; }
  location = /robots.txt  { access_log off; log_not_found off; }

  error_page 404 /index.php;

  // phpファイルはfastcgi(=php-fpm)で処理するよって書いてある
  location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    // ホスト名(=コンテナ名):ポート
    fastcgi_pass php:9000;
    fastcgi_index index.php;
    include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }
  location ~ /\.(?!well-known).* {
      deny all;
  }
 }

LaravelをNginxで動作させる設定です。 ApacheではLaravel同梱の.htaccessが設定してくれるが、Nginxでは.htaccessに当たるものがないためNginxのconfを修正する必要がある。(.htaccessを極力使わないほうがいい

公式の設定Nginx | laravel.comからphpコンテナのfpmを見るよう修正しています。 ネットワークはDockerに管理されており、ホスト名はコンテナ名と同等です。

ドキュメントルートを/var/www/laravel/publicとしています。 プロジェクト名が変わるときはパスに注意。

docker-composeのコマンド

ホスト側でよく使うコマンドです。

# コンテナ起動
$ docker-compose up -d

# コンテナ削除
$ docker-compose down

# コンテナ、イメージ、ボリューム、ネットワークを一括完全消去
$ docker-compose down --rmi all --volumes

# phpコンテナに接続する(コンテナ名を変えて他のコンテナに接続できる)
$ docker-compose exec php bash

Dockerfileなど修正した場合は一括削除してから起動しなおすといい。

初回はLaravel 8.x インストールに従ってphpコンテナ内で作業するとプロジェクトを作成できます。 ログの書き込みなどでpermission deninedが出る場合は、# chown -R www-data:www-data /var/wwwを実行するとphp-fpmに権限が与えられて解消できます。(php-fpmユーザを変更した場合はそのユーザ名にする)

参考

DockerFile

Dockerの操作

書籍

Docker実践ガイド 第2版 | amazon

Dockerって何?の状態で読むと難しすぎたが、Dockerの概念を他で学び試して遊んでからわかるようになった。 Dockerの運用管理向け、業務で何度も読み返しそうな良著。