【備忘録】DockerでのLaravel環境の構築

今更ながら、Dockerを使ってみようと思ったので友人が使っているというLaravelの環境をDockerで構築して使い方を学習しました。

# 環境
<d1> 実行環境
 <dt>・Windows10 Home WSL2</dt>
 <dt>・Docker Desktop</dt>
</d1>
<d1>使用イメージ（すべて公式イメージ）
 <dt> ・PHP</dt>
 <dt> ・composer</dt>
 <dt> ・nginx</dt>
 <dt> ・mysql</dt>
</d1>
Dockerのイメージは

[DockerHub](https://hub.docker.com/ "DockerHub")で入手できます。
```
docker pull nginx
docker pull php
docker pull composer
docker pull mysql
```
Dockerが実行できる環境であれば、これらのコマンドでイメージの入手ができます。

# 実行環境の準備
WSLとDockerの環境構築はMicrosoft Docを参照

https://docs.microsoft.com/ja-jp/windows/wsl/install

https://docs.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-containers

WSLはデフォルトで入っているっぽいので環境構築というよりもLinuxの種類の選択みたいな感じ
Dockerに関してはDocker Desktopをインストールすれば問題ない。（アカウントも作らなくて大丈夫）

# ディレクトリの構造
いくつかの参考ページをもとに以下のような形にしました。
![フォルダイメージ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687594/2fb85ec6-43b8-afc6-7252-8f9fa8e60727.png)

# ディレクトリ：php
PHPの設定とLaravelのインストールを行う設定を記述するファイルを置いているディレクトリです。
## php.iniの設定
ディレクトリの構造と同様にこちらも、いくつかの参考ページをもとに以下のように作成しました。
```php.ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"
[opcache]
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=1
```

前半は何となくわかるが、後半のopcaheについては、勉強不足でわかりません。
ただ、opcacheはPHPの処理を高速にするものらしい

https://weblabo.oscasierra.net/php-opcache/


## Dockerfile

```Dockerfile
FROM php:fpm

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

RUN apt-get update \
    && apt-get install -y zlib1g-dev \
    && apt-get install -y libzip-dev \
    && docker-php-ext-install zip pdo_mysql opcache

WORKDIR /var/www

COPY --from=composer /usr/bin/composer /usr/bin/composer

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

RUN composer global require "laravel/installer"
```

`Dockerfile`については上記のようにしました。
~~といっても参考サイトをほぼコピーしたようなものですが...~~

以下、`Dockerfile`の内容の~~考察~~ 解説となります。
興味がない場合は次の項目までスキップしてください。

コンテナのベースとなるイメージにはPHPの公式イメージを使っています。
```Dockerfile
FROM php:fpm
```
`/etc`という文言があるため、**php.iniの設定**で書いた`php.ini`を適用しているのはこの箇所だと思われます。
```Dockerfile
COPY php.ini /usr/local/etc/php/
```
ubuntuのパッケージ管理`apt`があるため、必要なパッケージのインストールを行っている。
`composer`の使用に必要なパッケージだそうです。
```Dockerfile
RUN apt-get update \
    && apt-get install -y zlib1g-dev \
    && apt-get install -y libzip-dev \
    && docker-php-ext-install zip pdo_mysql opcache
```

`WORKDIR`は名前から考えるにコンテナ内でコマンドを実行するディレクトリのするデフォルトの場所だと思われる。
```Dockerfile
WORKDIR /var/www
```
下記のコマンドでコンテナのshellに入ると`WORKDIR`で指定した箇所になっている。
```bash
docker-compose exec php bash
```

**composer**は普通ならコマンドでインストールするが、コンテナのイメージから使えるらしい。
composerのイメージからcomposerを取り出しの設定はおそらくここ
```Dockerfile
COPY --from=composer /usr/bin/composer /usr/bin/composer
```

`EMV`は環境変数の設定らしい
```Dockerfile
ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_HOME /composer
ENV PATH $PATH:/composer/vendor/bin
```
最後の`RUN`はcomposerでLaravelをインストールするコマンド
```Dockerfile
RUN composer global require "laravel/installer"
```
# ディレクトリ：nginx
webサーバはnginxで行いました。
Apacheの資料より、こっちの資料のが多かったのでnginxにしました。
nginxに置いているファイルは`default.conf`のみ
## default.conf
内容は下記のような感じ
```default.conf
server {
    listen 80;
    index index.php index.html;
    root /var/www/app/public;

    location / {
        root /var/www/app/public;
        index index.php;
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app: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`の内容の考察 解説となります。
興味がない場合は次の項目までスキップしてください。
~~私はnginxは使ったことがないためApacheの設定ファイルの知識の範囲で推測できることになります~~
```
listen 80;
index index.php index.html;
root /var/www/app/public;
````
この箇所はwebサーバの基本的な設定だと思われます。
上から、アクセスリクエストを受け付けるポートの番号、自動で読み込むファイルの名前、表示するファイルの場所であると思われます。（少なくとも上２つはほぼ確実）
```
location / {
        root /var/www/app/public;
        index index.php;
        try_files $uri $uri/ /index.php?$query_string;
    }
```
ここの設定はドメイン名やipアドレスでアクセスした際の設定
（http://locahlhost:80 でアクセスする際の設定）
最後の行だけは勉強不足でわかりません。後で調べようと思います。
```
location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
```
この箇所も勉強不足でほとんどわかりません。
何となくの推測ではCGIの設定だと思われます。最初の`try_files $uri =404;`の箇所と上から読み込みすると考えると、もしかしたら`index.php`にアクセスできなかった際の設定である可能性もある。

# docker-compose.ymlの設定
```docker-compose.yml
version: '3'

services:
  app:
    container_name: app
    build: ./docker/php
    volumes:
      - .:/var/www
  nginx:
    image: nginx
    container_name: "laravel-nginx"
    ports:
      - "8080:80"
    volumes:
      - .:/var/www
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
  mysql:
    image: mysql
    container_name: "laravel-mysql"
    restart: always
    environment:
      MYSQL_DATABASE: root
      MYSQL_ROOT_PASSWORD: root
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    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
```
以下、`docker-compose.yml`の内容の考察 解説となります。
興味がない場合は次の項目までスキップしてください。

`app:`、`nginx:`、`mysql:`の箇所がコンテナ１つ１つの設定の開始であると思われます。

`image:`は使用するイメージ。設定している箇所は`nginx`と`mysql`の２つ

`container_name`はコンテナの名前です。後述するlaravelの`.env`ファイルのホスト名がここで設定した名前になることから、コンテナのホストネームも`container_name`で設定した値になると思われます。

`valumes:`はデータのマウント元を設定する箇所であると思われる。おそらく`:`の左側に書かれたものがマウントするDockerのホスト側のディレクトリやファイル名、右側がコンテナのマウント先のディレクトリやファイルである。

`ports`も同様に`:`の左側がDockerのホスト側のポート番号、右側が転送するコンテナ側ポート番号であると思われます。

mysqlで設定されている`environment:`はデータベース側の設定で、`MYSQL_DATABASE: root`、`MYSQL_ROOT_PASSWORD: root`が管理ユーザーの設定、`MYSQL_USER: user`、`MYSQL_PASSWORD: password`が一般ユーザーの設定である。
`command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci`はコンテナ内で実行するコマンドである。
# コンテナの作成
作成するコンテナの設定が完了したため、このコマンドでコンテナを作成します。
```bash
docker-compose up -d
```
実行後にこのコマンドでコンテナが無事に立ち上がっているかが確認できます。
```bash
docker-compose ps
```
正常に起動した場合はこのようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687594/9f650e5d-6f26-69b0-da83-b52931897ee1.png)

# Laravelの設定
コンテナが立ち上がったところで、LaravelのインストールとMySQLとLaravelの接続の設定を行う。
このコマンドでappコンテナのシェルに入る。
```bash
docker-compose exec app bash
```
次に、このコマンドでLaravelのインストールが行える。`laravel`の部分がインストールするLaravelのフォルダ名となる。
```bash
composer create-project --prefer-dist laravel/laravel laravel
```
MySQLとLaravelの接続の設定を行います。
インストールしたlaravelの直下に配置されている`.env`ファイルを編集する。
Linuxシステムにおいて先頭に`.`が付くファイルは隠しファイルとなるため、`ls`コマンドでは表示されません。`ls -a`オプションを追加することで隠しファイルも含めたファイルの一覧を表示することができます。（VSCodeだと普通に表示されていましたが...）
```.env
DB_CONNECTION=mysql
DB_HOST=laravel-mysql
DB_PORT=3306
DB_DATABASE=laravel_database
DB_USERNAME=user
DB_PASSWORD=password
```
`.env`の中で書き換えるのはこの箇所
上から接続するデータベースの種類（PostgreSQLの場合は、ここの値を書き換える）
`DB_HOST`はデータベースのホスト名を指定する箇所です。`docker-compose.yml`で設定したmysqlの`cantainer_name`の値に書き換える。
'DB_PORT'も同様にmysqlの`ports`で指定した値を設定する。
`DB_USERNAME`、`DB_PASSWORD`も同様に`environment:`で設定した値に書き換える。
普通なら管理者ユーザーではなく一般ユーザーで作成するほうがベター

私の環境では一般ユーザーでのマイグレーション時に権限不足で実行することができませんでした。
MySQLのクライアントを入れていない場合は、
```
docker-compose exec mysql mysql -uroot -p
```
で管理者ユーザーとしてMySQLにログインし、Laravel用のデータベースを作成と一般ユーザーに作成したデータベース内での権限を与えればマイグレーションの実行ができました。

# 履歴
2022年４月３日：新規作成