Laravel の開発環境を homestead から Sail(Docker) にしてみる

# はじめに
つい最近まで Laravel の公式ドキュメント上で一番開発しやすそうな環境は VirtualBox + Vagrant の Homestead だなぁと個人的には思っていたのですが、昨今では [Laravel Sail](https://github.com/laravel/sail/) という、Docker をベースとしたコンテナ形の開発環境をコマンド１発で作れるようになったので新規案件から乗り換えてみることにしました。  
ただ、使い勝手が変わってきますので半分備忘録ですが Homestead でやっていた時の感覚のままをなるべく移行できるように、気をつけるべきポイントを残しておきます。

なお、動作は全て MacOS 上での結果です。
大前提として [Docker Desktop](https://www.docker.com/products/docker-desktop) は入れておいてください。

## インストール

```shell
curl -s https://laravel.build/example-app | bash
```

`example-app` は任意で、この名前のフォルダが生成され、Laravel の構成ファイルはその中に展開されます。  
パイプの後ろに `bash` となってますが、おそらく互換性があるシェルなら何でも良さそうです。なので自分は `zsh` としてみましたが問題なく動きました。

## sail コマンド

まずは作ったプロジェクト（さっきの example-app）にディレクトリは移動しておきましょう。

```shell
cd example-app
```

この時、今後 `sail` というコマンドを一々相対パスやフルパスで打たないといけないのは面倒なので、プロジェクトフォルダの最上位という制限付きにはなりますがコマンド名だけでうてるように alias を入れておくと便利になります。

```shell
alias sail="./vendor/bin/sail"
```


## 起動前の変数設定
.env ファイルを読み込んで変数を設定できるようになっています。

先頭付近にでも足しておくと良いのはこの辺り。

```shell:.env
APP_SERVICE=example       # 案件名とかにすると良いです。デフォルトは laravel.text
APP_PORT=80               # ブラウザでみる時のポート。複数案件同時起動に支障をきたすので任意で変えましょう。デフォルトは 80
FORWARD_DB_PORT=3306      # MySQL の Listen ポート。これも複数案件同時起動時は任意の数字に変更しましょう。デフォルトは 3306
DB_ROOT_PASSWORD=password # MySQL の root パスワード。
```


これに合わせて `docker-compose.yml` についても一部調整しましょう。

```yml:docker-compose.yml

version: '3'
services:
    example: # ここは任意で変更可能。案件名にしておくと良いかも
        build:
            context: ./vendor/laravel/sail/runtimes/8.0
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-8.0/app
        ports:
            - '${APP_PORT:-80}:80'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
        depends_on:
            - mysql
            - redis
            - selenium
    mysql:
        # image: 'mysql:5.7' # バージョン違いも利用できる
        image: 'mysql:8.0'
        ports:
            - '${FORWARD_DB_PORT:-3306}:3306'
        environment:
            MYSQL_ROOT_PASSWORD: '${DB_ROOT_PASSWORD}' # '${DB_PASSWORD}' から変更
            MYSQL_DATABASE: '${DB_DATABASE}'
            MYSQL_USER: '${DB_USERNAME}'
            MYSQL_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
(略)
        # MySQL の一部不要エラーメッセージを消すために入れておくことを推奨
        cap_add:
          - SYS_NICE
(略)
    # 不要なコンテナはコメントしておくと起動しなくなる
    # selenium:
    #    image: 'selenium/standalone-chrome'
    #    volumes:
    #         - '/dev/shm:/dev/shm'
    #    networks:
    #        - sail
```

ここまでやったら起動です。
MySQL については [公式ドキュメント](https://hub.docker.com/_/mysql) のパラメータを参考にしてください。


## コンテナ起動

```shell
sail up -d
sail up
```

どちらでも良いです。お好きな方で。
初回だけイメージ作成を行うので時間が結構かかります。


## コンテナ停止

ctrl + c で止めるか、`sail down` で停止です。後者はコンテナごと消えます。
注意しないといけないのは、コンテナを停止時、削除を行なっても Volume は消えません。

```shell
docker volume ls 
```

このコマンドを叩くと、コンテナは消えてるのにボリュームだけ残ってることが確認できると思います。
逆に言えば MySQL のデータとかは永続的に保持されるということなんですが、消したい場合はちゃんとオプションを与えてあげないといけません。

sail コマンドは基本的に[`docker-compose`コマンド](https://docs.docker.jp/compose/reference/overview.html)の拡張になっています。なので原則、 `docker-compose` のオプションは全部使えると思って差し支えありません。
よって全てを消し去りたい、と思ったら

```shell
sail down --volumes（または-v）
```

と、--volumes というオプションをつけてやればボリュームまできれいさっぱり消えます。
さらにイメージも含めて本当に何もかも、という究極の削除は以下の通り。利用にはご注意を。

```shell
sail down --volumes --rmi all --remove-orphans
```

## Laravel Mix

公式ドキュメントには

```shell
sail npm run prod
```

こんなふうに sail 経由で npm 叩けますよ、って書いてあるんですが、確かにその通りなんですが実行する場所が「コンテナ側か」「自分のパソコン側か」という視点で見た時、私がよく使う Browser Sync などは当然自分のパソコン側で動かないと意味がありません。
なので `npm` を動かす側で `npm install` を行う必要がありますので、sail 経由では実行しないようにしましょう。

```js:webpack.mix.js
mix.browserSync({
    proxy: '127.0.0.1:80/',
    port: 3200,
    files: [
        'public/html/**/*.html',
        'app/**/*.php',
        'resources/views/**/*.php',
        'public/common/js/**/*.js',
        'public/common/css/**/*.css',
    ]
});
```

こんな感じで BrowserSync の設定を入れておくと、 `npm run watch` などで起動した時に勝手に必要なモジュールはインストールされて起動させることができます。初回はインストールだけ走って止まってしまった場合はもう一度同じコマンドを実行してください。
127.0.0.1 の後ろのポート番号は `APP_PORT` と合わせておきましょう。

## Artisan
マイグレーションについては正直、コンテナの仮想マシン側でも自分のPC側でも、.env の設定次第でどうにでもなりますので気にしなくて良いと思います。
お好きな方でどうぞ。

```shell
sail artisan migrate
php artisan migrate
```

ただし .env 内のDB系パラメータのうち、

```shell:.env
DB_HOST=mysql
DB_PORT=3306
```

この二つはコンテナ内部から見た場合、にしないといけません。なのでここは固定のままにしておくほうがよく、利用するのも sail コマンド経由がよろしいかと思います。