DockerでLEMP環境を構築する

## 前提
OSはMacOSで行います。
DockerやDocker-composeは使用できる前提で進めます。

```
docker -v
docker-compose -v
```

## 必要なディレクトリを作成する

```
# プロジェクトのルートディレクトリを作成する
mkdir 【ルートディレクトリ名】

cd 【ルートディレクトリ名】
mkdir docker
cd cdocker
mkdir app web db
```

下記の構成になっていればOK

```
【ルートディレクトリ】
└─ docker
    ├─ app
    │  └─ Dockerfile
    │  └─ php.ini
    ├─ web
    │   └─ Dockerfile
    │   └─ default.conf
    └─ db
        └─ Dockerfile
        └─ my.cnf 
```


## docker-compose.ymlを作成する

```
# versionはComposeファイルのバージョンでありDocker Compose自体のバージョンとは異なることに注意
version: '3.8'

volumes:
  mysql-volume:

services:
  # サービス名: PHP
  app:
    build:
      context: .
      dockerfile: ./docker/app/Dockerfile
    volumes:
      - ./src/:/var/www/html
    # 環境変数を設定(.envに紐づく)
    environment:
      - DB_CONNECTION=mysql
      - DB_HOST=db
      - DB_PORT=3306
      - DB_DATABASE=${DB_NAME}
      - DB_USERNAME=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}

  # サービス名: Nginx
  web:
    # ビルドするDockerfileの指定
    build:
      context: .
      dockerfile: ./docker/web/Dockerfile
    # ローカル(PC)とDockerコンテナ間のポート番号の対応づけを設定{ローカル}:{Dockerコンテナ}
    ports:
      - ${WEB_PORT}:80
    # コンテナ間の依存関係を設定(appはPHPアプリケーションのコンテナを指す)PHP->Nginxの順にコンテナを起動させる
    depends_on:
      - app
    # ローカルとDockerコンテナ間のディレクトリ・ファイル等のリソースを対応づける設定(ローカルのリソース:Dockerコンテナ内のリソース)
    volumes:
      - ./src/:/var/www/html

  # サービス名: MySQL
  db:
    build:
      context: .
      dockerfile: ./docker/db/Dockerfile
    # ローカルのポート番号(MySQLのデフォルトのポート番号は3306)
    ports:
      - ${DB_PORT}:3306
    # MySQLの環境変数
    environment:
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      TZ: 'Asia/Tokyo'
    volumes:
      - mysql-volume:/var/lib/mysql
```

## .envファイルの作成
下記を実行する

```
touch .env
# .gitignoreを作成して.envを記載する
touch .ignore
```

```
# db/environmentの部分はここの環境変数を参照している
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
```

## 各Dockerfileを作成する
#### ■PHPに対してDockerfileを作成
【ルートディレクトリ】/docker/app下にDockerfileを作成する

```
# イメージのベースを指定する
FROM php:7.4.1-fpm

# php.iniをコピー
COPY ./docker/php/php.ini /usr/local/etc/app/php.ini

# Composer install
COPY --from=composer:2.0 /usr/bin/composer /usr/bin/composer

#node.js install(reactを使用するため)
COPY --from=node:10.22 /usr/local/bin /usr/local/bin
COPY --from=node:10.22 /usr/local/lib /usr/local/lib

# パッケージ管理ツール(apt)-getの更新と各パッケージやphp拡張モジュールのインストール
RUN apt-get update \
    && apt-get install -y \
    git \
    zip \
    unzip \
    vim \
    && docker-php-ext-install pdo_mysql bcmath

# コンテナでの作業ディレクトリを指定(docker-compose exec app bashを利用した時のカレントディレクトリになる)
WORKDIR /var/www/html
```

#### ■Nginxに対してDockerfileを作成
【ルートディレクトリ】/docker/web下にDockerfileを作成する

```
FROM nginx:1.18

# 環境変数（TZ）を定義
ENV TZ=UTC

# nginx config file,  Nginxの設定ファイルをコンテナ内にコピーして対応づける
COPY ./docker/web/*.conf /etc/nginx/conf.d/

WORKDIR /var/www/html
```

#### ■MySQLに対してDockerfileを作成
【ルートディレクトリ】/docker/db下にDockerfileを作成する

```
FROM mysql:8.0

ENV TZ=UTC

COPY ./docker/db/my.cnf /etc/my.cnf
```

## 各ミドルウェアの設定ファイルを作成する
### ■PHPの設定ファイルを作成
【ルートディレクトリ】/docker/app下にphp.iniを作成する

```
# タイムゾーンの設定
[Date]
date.timezone = "Asia/Tokyo"

# 日本語環境の設定
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"
```

### ■Nginxの設定ファイルを作成
【ルートディレクトリ】/docker/web下にdefault.confを作成する

```
server {
    listen 80;

    root /var/www/html/public;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

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

    index index.php index.html index.htm;

    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;

    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}
```

下記を参照
https://readouble.com/laravel/6.x/ja/deployment.html#server-configuration

### ■MySQLの設定ファイルを作成
【ルートディレクトリ】/docker/db下にmy.cnfを作成する

```
[mysqld]
user=mysql
character_set_server = utf8mb4
collation_server = utf8mb4_0900_ai_ci

# timezone
default-time-zone = SYSTEM
log_timestamps = SYSTEM

# Error Log
log-error = mysql-error.log

# Slow Query Log
slow_query_log = 1
slow_query_log_file = mysql-slow.log
long_query_time = 1.0
log_queries_not_using_indexes = 0

# General Log
general_log = 1
general_log_file = mysql-general.log

[mysql]
default-character-set = utf8mb4

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

## dockerイメージを作成
【ルートディレクトリ】下にsrcフォルダを作成する

```
mkdir src
```


【ルートディレクトリ】で下記を実行する

```
docker-compose build
```


## コンテナを起動する
【ルートディレクトリ】で下記を実行する

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

startedが表示されるとコンテナがバックグランドで起動してDockerでのLEMP環境を構築できました！

## Laravelをインストールする
【ルートディレクトリ】で下記を実行する

```
# appコンテナへ入る
docker-compose exec app bash

# composerが入っているかを確認する
composer -v

# Laravelプロジェクトを作成する
composer create-project --prefer-dist "laravel/laravel=【バージョン】" .
```

【ルートディレクトリ】/srcにLaravelで使用するファイルやディレクトリが作成されているのを確認する

localhost:80でLaravelのウェルカムページが表示されていることを確認する

ReactやVueなども使用したい時もLaravelと同様にdocker-compose exec app bash内でnpm installを実行すれば使用できます。

## 最終的なディレクトリー階層

```
【ルートディレクトリ】
├─ docker
│    ├─ app
│    │   └─ Dockerfile
│    │   └─ php.ini
│    ├─ web
│    │    └─ Dockerfile
│    │    └─ default.conf
│    └─ db
│         └─ Dockerfile
│         └─ my.cnf 
├─ src
│   └─ 【Laravelのパッケージ】 
│─ .env
│─ .gitignore   
└─ docker-compose.yml
```