DockerでLaravel開発環境を構築したメモ

# 前提・やること
- 既に作成されているLaravelプロジェクトを、docker環境をWindowsに作ってソース移行し、動くように（デプロイ）する。
コンテナはphp、nginx、mysql、phpmyadmin。

- Docker Desktop for windows 、WSLはインストール済。

- 下記の参考サイトを手順に環境を作成し、追加で独自カスタマイズ、および出たエラー対応をしていく。
[DockerでLaravel開発環境を手軽に構築する手順 - カゴヤのサーバー研究室](https://www.kagoya.jp/howto/cloud/container/docker_laravel/)
- ※最初、以下の記事を参考に作成しようとしたら、nginxが起動してもすぐに停止する、ブラウで502 Bad Gateway のエラーがどうしても解決できなかったので、別の記事を参考にした。
https://reffect.co.jp/laravel/finally-understand-laravel-on-docker#Laravel-3

# 環境
windows11 home
WSL2
Docker Desktop for windows v4.18.0
Laravel 10
PHP8.2

# 環境構築
## 参考サイトを元に進める
https://www.kagoya.jp/howto/cloud/container/docker_laravel/
を参考に進めていく。
- PowerShellで任意の場所に作業フォルダ　laravel_docker　を作成し、そのフォルダに移動。
```PowerShell
mkdir laravel_docker
cd laravel_docker
```
- laravel_dockerディレクトリ配下に以下のようにディレクトリ・ファイルを作成していく。（参考サイトの図参照）
laravel_docker配下

├docker├ nginx
│　　　│　 └default.conf
│　　　└ PHP
│　　　　　└Dockerfile 
│　　　　　└PHP.ini
└compose.yml


- compose.yml
laravel_dockerディレクトリ配下に保存。
```compose.yml
services:
  app:
    container_name: app
    build: ./docker/php
    volumes:
      - .:/var/www
  nginx:
    image: nginx
    container_name: nginx
    ports:
      - 9000:80
    volumes:
      - .:/var/www
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    working_dir: /var/www
    depends_on:
      - app
  db:
    image: mysql:5.7
    container_name: db
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
      MYSQL_USER: db-user
      MYSQL_PASSWORD: db-pass
      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
```

- php.ini
docker\php 内に保存
ここで、「mbstring.internal_encoding = "UTF-8"」
は最初に;を付けてコメントにする。のちにエラーになったため
参考：https://desuto.net/use-of-mbstring-internal_encoding/
```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
```

- Dockerfile
docker\php 内に保存
```Dockerfile:Dockerfile
FROM php:8.2-fpm
COPY php.ini /usr/local/etc/php/

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

#Composer install
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin


WORKDIR /var/www

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

- Webサーバー「nginx」の設定ファイル「default.conf」を作成。
ここで、
`try_files $uri $uri/ /index.php$query_string;`
の行は、のちにLaravelでgetパラメータが渡らないバグの原因となったので、
`try_files $uri $uri/ /index.php?$query_string;`
と修正。

```default.conf
server {
listen 80;
root /var/www/laravel-project/public;
index index.php;
location / {
root /var/www/laravel-project/public;
index index.php;
# try_files $uri $uri/ /index.php$query_string;
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;
}
}
```

- compose.ymlを使い、Dockerコンテナを起動。
```powershell
docker compose up -d
```
Dockerコンテナが正常に起動していることを確認。
```powershell
docker compose ps
```
正常に起動していれば、コンテナ一覧がSTATUS　UPで表示される。
```powershell
docker compose ps
NAME                                IMAGE                      COMMAND                  SERVICE             CREATED             STATUS              PORTS
app                                 docker_kagoya_ubuntu-app   "docker-php-entrypoi…"   app                 4 hours ago         Up 4 hours          9000/tcp
db                                  mysql:5.7                  "docker-entrypoint.s…"   db                  4 hours ago         Up 4 hours          0.0.0.0:3306->3306/tcp, 33060/tcp
nginx                               nginx                      "/docker-entrypoint.…"   nginx               4 hours ago         Up 4 hours          0.0.0.0:9000->80/tcp
```

- 作成したDockerコンテナの中へ入り、Laravelアプリを作成。
```powershell
docker compose exec app bash
```
- Dockerコンテナの中に入って、以下コマンドを実行。
```powershell
composer create-project --prefer-dist laravel/laravel laravel-project "10.*"
```
lsコマンドを実行で、以下のようにLaravelアプリが作成されたことを確認できる。

- storageディレクトリの所有者をwww-dataに変更。
```powershell
cd laravel-project
chown www-data storage/ -R
```

- Laravelが起動したことを確認するため、ブラウザで以下URLへアクセス。
http://DockerがインストールされたサーバーのIPアドレス:9000
（今回の場合、http://localhost:9000/）
成功していれば、以下のようにLaravelのウェルカムページが表示される。
![230429_000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3331757/36ea4358-22f6-8100-f555-eb7bfdf35aea.jpeg)

- ここまでが、参考サイトによる構築。
ここからさらに変更を加えていく。

## phpmyadminを追加
次に、phpmyadminを追加してみる。
compose.ymlの下部に下記を追加して、コンテナを作り直す。
```compose.yml
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=mysql
      # - PMA_USER=user
      # - PMA_PASSWORD=password
    links:
      - db
    ports:
      - 8081:80
    volumes:
      - /sessions
volumes:
  mysql-data:
```
すると、http://localhost:8081/
でphpMyadminが起動、
サーバ：db
ユーザ名：root
パスワード：root
で入ることができた。

## DBのmigrate
- laravelからの接続
Laravelルートにある.envファイルを開き、データベース接続を設定。
DB名、ユーザ名、パスワードなどを先ほどdocker-compose.ymlに設定した値に合わせる。
```.env
DB_CONNECTION_=mysql
#DB_HOST：container_name を入れる↓
DB_HOST=db
DB_PORT=3306
DB_DATABASE=（任意）
DB_USERNAME=root
DB_PASSWORD=root
```
設定後、
```powershell
php artisan config:cache
```
でキャッシュクリア。
次にappコンテナの中に入って、
```powershell
docker compose exec app bash
```
```powershell
php artisan migrate
```
をしてエラーが出ず、テーブルが作成されればLaravelとmysqlコンテナが接続完了。
```powershell
# php artisan migrate
   INFO  Preparing database.
  Creating migration table ......................................................................... 56ms DONE

   INFO  Running migrations.

  2014_10_12_000000_create_users_table ............................................................. 66ms DONE
  2014_10_12_100000_create_password_reset_tokens_table ............................................. 47ms DONE
  2014_10_12_100000_create_password_resets_table ................................................... 36ms DONE
  2019_08_19_000000_create_failed_jobs_table ....................................................... 48ms DONE
  2019_12_14_000001_create_personal_access_tokens_table ............................................ 56ms DONE
  2023_02_19_045335_create_people_table ............................................................ 16ms DONE
  2023_02_19_085749_create_boards_table ............................................................ 18ms DONE
  2023_02_20_055257_create_restdata_table .......................................................... 18ms DONE
  2023_02_20_234754_create_sessions_table .......................................................... 94ms DONE
  2023_03_11_144738_add_column_to_users_table ...................................................... 34ms DONE
```



## laravelのログイン機能を付ける
appコンテナの中に入る。
```powershell
docker compose exec app bash
```

https://readouble.com/laravel/10.x/ja/starter-kits.html
を参考にLaravel Breezeをインストール。
```bash
composer require laravel/breeze --dev
php artisan breeze:install
php artisan migrate
npm install
npm run dev
npm run build
```

途中でnpmがないと言われるので、
https://www.softel.co.jp/blogs/tech/archives/6487
こちらを参考にインストール（rootでない人は、随時先頭にsudoを付けて実行）。それから続きを再開。
```bash
apt install nodejs npm
npm install -g n
n stable
apt purge nodejs npm
exec $SHELL -l
```
```bash
バージョンを確認
node -v
v18.16.0
npm -v
9.5.1
```
これで、Laravel画面の右上にログインリンクが付く。
![230429_000002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3331757/35bcecee-9454-0966-655b-68eab3d7896e.jpeg)

- 環境設定は基本的にこれでOK。




次に、既存の環境からソースを移行して、デプロイしてみる。
ソースを移行し、動作させたところ、ログイン画面が正常に表示されない。
Vite manifest not found at: /var/www/laravel-project/public/build/manifest.json
エラー。
https://biz.addisteria.com/laravel_vite_errors/
このページを参考に、
```bash
npm run build
```
を実行したら、正常なページが出るようになった。

- 次に、Laravelトップ画面に下記のエラーが出るようになり、
`file_put_contents : failed to open stream: No such file or directory`
https://prograshi.com/framework/laravel/error-file_put_contents/
このページの対処法で解決した。
`$ php artisan config:cache`
`$ php artisan config:clear`
`$ composer dump-autoload -o`

- storageフォルダへのシンボリックリンクを張る
storageフォルダ内にある、画像アップロードした画像が表示されないので、シンボリックリンクを張る。
>storage/app/publicディレクトリは、プロファイルアバターなど、一般にアクセス可能である必要のあるユーザー生成ファイルを保存するために使用します。このディレクトリを指すシンボリックリンクをpublic/storageに作成する必要があります。php artisan storage:link Artisanコマンドを使用してリンクを作成できます。
https://readouble.com/laravel/10.x/ja/structure.html

appコンテナの中に入って
```powershell
docker compose exec app bash
```
```bash
# php artisan storage:link

   INFO  The [public/storage] link has been connected to [storage/app/public].
```
することで、リンクが作られた。
そのほか、独自に使用しているシンボリックリンクがあれば、それも作成する。
例）
ln -s /var/www/laravel-project/storage/app/public/upload upload
（\laravel-project\storage　フォルダで実行）

## 動作の重さ改善（ubuntu内にファイル移転）
ここまでで、既に動いているLaravelのソースを移行し、おおよその動作確認はできた。が、ものすごく動作が重い。簡単な画面遷移で5～10秒ぐらいかかる感じ。
これは下記による問題のようなので、これを改善してみる。

WindowsでDockerを使う時、正しくファイル配置しないと激重になるので注意
https://qiita.com/minato-naka/items/84508472c04f628e576e

Windows内にubuntuをインストールし、アプリコードをその中に置くと早くなるとのこと。
そこで上記の記事を参考にやってみる。

- Ubuntu-22.04をインストールして再起動。
エクスプローラーでのパスが
\\wsl$\Ubuntu-22.04
となるので、作業フォルダを今回、docker_kagoya_ubuntu　として、
・docker作業フォルダ
\\wsl.localhost\Ubuntu-22.04\home\\<ユーザー名>\docker_kagoya_ubuntu
・Laravelフォルダ
\\wsl.localhost\Ubuntu-22.04\home\\<ユーザー名>\docker_kagoya_ubuntu\laravel-project
として、dockerを起動。
起動はできるが、
http://localhost:9000/
でエラー出る。
`
The stream or file "/var/www/laravel-project/storage/logs/laravel-2023-04-29.log" could not be opened in append mode: Failed to open stream: Permission denied The exception occurred while attempting to log: The stream or file
`

- パーミッションが何とかと言っているので、パーミッション設定をしてみる。
```powershell
docker compose exec app bash
```
で中に入り、
https://qiita.com/ky-jp16/items/9956ea9dd391f0d69127
を参考にパーミッションを設定。
エラーは解消。

## ubuntu内のファイルを編集できるように対応
- その後、アプリのソースを一部変更しようとしたところ、権限がなくファイルを変更できない、とエラー。
>WSL 2 の Linux ファイルシステムを bind mount してコンテナー内開発を行う場合、権限を適切に設定しないと、コンテナー内で作成したファイルが、ホストの WSL 2 や Windows 側で操作できなくなってしまうなどの問題が発生します。
https://futureys.tokyo/how-permission-should-be-set-for-developing-inside-a-container-using-wsl-2/
WSL で デフォルトユーザ を変更する方法
https://devlights.hatenablog.com/entry/2021/05/29/070000

上記の記事を参考に対応。
管理者権限でPowerShellを起動し、
```powershell
ubuntu2204  config --default-user root
```
でファイルが編集できるようになった。

- ここまでの状態で、とりあえず完了。
アプリのソースファイルをubuntu内に移動したことによって、移行したLaravelアプリの動作が劇的に軽くなり、問題なく動くようになった。

※後に気づいた点があったら追記します。