php7.4のLaravel環境をDockerでつくる

## はじめに

DockerでLaravel環境作ってログインできるまでをハンズオン形式で進めます。
ローカル環境ちゃちゃっと作って開発したい人向けなので、詳細説明はありません。
せっかくなので最近リリースされたPHP7.4を使ってみます。

## 環境

* php7.4
* Apache2
* MySQL5.7

## 0. 事前準備

### Dockerインストール

Mac,Windows ProならDocker、Homeならdocker toolbox
dockerならHyper-V設定も忘れずに

会社でよくあるWindowsProなら↓を参考に
https://www.koreyome.com/web/docker-install-for-windows/
0. CPU仮想環境設定を確認
1. Hyper-V設定
2. Dockerインストール
3. docker-compose

インストール確認

```bash
$ docker-compose -v
```

### VSCodeのターミナルを準備(任意)

初心者でもつまずかないよう統一して VSCode の Terminal を git bash にしています。
GitBashは入っている前提です。

1. setting表示 (Ctl+,)
1. terminal.integrated.shell.windows 入力
1. Edit in settings.json 選択
1. GitBash 選択  
    (例) `"terminal.integrated.shell.windows": "C:\\Program Files\\Git\\bin\\bash.exe"`
1. Terminal表示(Ctl+Shift+@)
1. 1:bash になる

## 1. ディレクトリ構成とファイル作成

ディレクトリ構成は下記のようになります

```
docker
├── db
│   └── my.conf
├── php-apache
│   ├── 000-default.conf
│   ├── default-ssl.conf
│   ├── php.ini
│   └── Dockerfile
├── .env
└── docker-compose.yml
```

クローンしてもいい

```bash
git clone https://github.com/qvtec/laravel-docker-base.git
```

#### Dockerfile 作成

composer も node もインストールしているので、別コンテナに分けた方がいいかも

```dockerfile:Dockerfile
FROM php:7.4.0-apache

COPY ./php.ini /usr/local/etc/php/
COPY ./sites/*.conf /etc/apache2/sites-available/

ARG TZ=Asia/Tokyo
ARG NODE_VERSION=8.x

RUN set -xe; \
    apt-get update -yqq && \
    apt-get install -yqq --no-install-recommends \
      apt-utils vim gettext git \
      default-mysql-client \
      # for gd
      libfreetype6-dev \
      libjpeg62-turbo-dev \
      libpng-dev \
      libwebp-dev \
      libxpm-dev \
      # for ImageMagick
      libmagickwand-dev \
      # for zip
      libzip-dev zip unzip \
      # for oniguruma
      libonig-dev \
    && docker-php-ext-install bcmath gettext mbstring mysqli pdo pdo_mysql zip \
    && docker-php-ext-configure mbstring --disable-mbregex \
    && docker-php-ext-configure zip --with-libzip \
    # gd
    && docker-php-ext-install -j$(nproc) iconv \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd \
    # imagick
    && pecl install imagick \
    && docker-php-ext-enable imagick \
    # exif
    && docker-php-ext-install exif \
    && docker-php-ext-enable exif \
    # enable mod_rewrite
    && a2enmod rewrite \
    # enable ssl
    && a2enmod ssl \
    # enable site
    && a2ensite default-ssl \
    # for ssl
    && apt-get update \
    && apt-get -y install ngrep \
    && openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj "/C=JP/CN=localhost" \
        -keyout /etc/ssl/private/apache-selfsigned.key -out /etc/ssl/certs/apache-selfsigned.crt \
    # set timezone
    && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
    # node
    && curl -sL https://deb.nodesource.com/setup_$NODE_VERSION | bash - \
    && apt-get install -y nodejs npm \
    # install composer
    && cd '/' \
    && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
    && php composer-setup.php \
    && php -r "unlink('composer-setup.php');" \
    && mv composer.phar /usr/local/bin/composer

ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_HOME /composer
ENV PATH $PATH:/composer/vendor/bin

# laravel installer
RUN composer global require "laravel/installer" \
    && composer global require "laravel/envoy"

WORKDIR /var/www/html
```

#### docker-compose.yml 作成

* work : phpとapacheがあるメインのコンテナ
* mysql
* phpmyadmin
* redis

``` yml:docker-compose.yml
version: '3'

services:
  work:
    build:
      context: ./php
    volumes:
      - ${PROJECT_PATH}:/var/www/html:cached
      - node_modules:/var/www/html/node_modules
    ports:
      - ${WEB_PORT}:80
      - ${WEB_SSL_PORT}:443
    depends_on:
      - mysql

  mysql:
    image: mysql:5.7
    volumes:
      - mysql_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASS}
      TZ: ${TZ}
    ports:
      - ${DB_PORT}:3306

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=mysql
      - PMA_USER=root
      - PMA_PASSWORD=root
    ports:
      - ${PMA_PORT}:80

  redis:
    image: redis:latest
    ports:
      - ${REDIS_PORT}:6379
    volumes:
      - redis_data:/data
    command: redis-server

volumes:
  mysql_data:
  node_modules:
  redis_data:
```

#### .env 作成

COMPOSE_PROJECT_NAME はプロジェクト名に変更する
使っていないポートにする

``` :.env
COMPOSE_PROJECT_NAME=laravel-docker-base
PROJECT_PATH=../src

WEB_PORT=80
WEB_SSL_PORT=443
DB_PORT=3306
PMA_PORT=8080
REDIS_PORT=6379

TZ=Asia/Tokyo
DB_NAME=docker
DB_USER=docker
DB_PASS=secret
```

#### apache conf 作成

httpとhttpsの両方を作成してみます

``` 000-default.conf
<VirtualHost *:80>
  ServerName local.test.com
  DocumentRoot /var/www/html/public/

  <Directory /var/www/html/public>
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    Require all granted
  </Directory>

  ErrorLog /var/log/apache2/error.log
  CustomLog /var/log/apache2/access.log combined
</VirtualHost>
```

httpsで接続しない場合は、ssl用のconfファイルが不要で
Dockerfile の `a2ensite default-ssl` と # for ssl の項目も不要です

``` default-ssl.conf
<IfModule mod_ssl.c>
    <VirtualHost _default_:443>
        ServerName local.test.com
        DocumentRoot /var/www/html/public
        ErrorLog /var/log/apache2/error.log
        CustomLog /var/log/apache2/access.log combined
        SSLEngine on
        SSLCertificateFile /etc/ssl/certs/apache-selfsigned.crt
        SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key
        <FilesMatch "\.(cgi|shtml|phtml|php)$">
            SSLOptions +StdEnvVars
        </FilesMatch>

        <Directory /usr/lib/cgi-bin>
            SSLOptions +StdEnvVars
        </Directory>
        Options Indexes FollowSymLinks

        <Directory "/var/www/html/public/">
            AllowOverride All
            Require all granted
        </Directory>
    </VirtualHost>
</IfModule>
```

#### php 設定ファイル

``` ini:php.ini
[Date]
date.timezone = "Asia/Tokyo"

[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"
```

#### mysql 設定ファイル

``` my.conf
[mysqld]
character-set-server=utf8
datadir = /var/lib/mysql
```

## 2. Docker起動

### docker設定ファイルの作成

cloneしている場合は.env.exampleをコピーして.envを修正する

```
cd docker/
cp .env.example .env
```

### ビルドと起動

```bash
docker-compose up -d --build
```

### コンテナ接続

```bash
docker-compose exec work bash
```


## 3. Laravelインストール

workコンテナで実行する

### Laravelプロジェクト作成

```bash
laravel new
```

src以下にlaravel新規プロジェクトがマウントされる
.env設定ファイルも作成されている

### Laravel設定ファイル

src/.env を修正する

```
DB_HOST=mysql
DB_USSERNAME=root
DB_PASSWORD=root

CACHE_DRIVER=redis
REDIS_HOST=redis

MAIL_DRIVER=log
```

## 4. hosts設定と表示

```
127.0.0.1 local.admin.com
```

https://local.admin.com/

表示できましたか？


## エラー対応

ハンズオンでエラーになった人がいたので対処法

> ERROR: for web  Cannot create container for service web: b'Drive sharing failed for an unknown reason'
> ERROR: Encountered errors while bringing up the project.

bドライブ使ってないと思うので、dockerの設定変更が必要
http://kdnakt.hatenablog.com/entry/2019/09/12/080000

> xamppでmysqlが接続できなくなった

ポート変更が必要
.envで3306→3316とか使ってないポートに変更する


## さいごに

laradockを使っていましたが遅かったので、phpの公式のphp-apacheを使うようになりました。
まだdocker歴が短いので、ベストな状態かはわかりません。
なにかあれば教えてください。