Laravel SailでLaravel 9 (PHP8.1 + node.js 16.x) 環境をサクッと立ち上げる

# はじめに

Laravelの作業を始めるときは、まずLaravel用のdocker-compose.yml他一式を準備していましたが、今ではデフォルトでLaravelのDocker構築環境[Laravel Sail](https://laravel.com/docs/9.x/sail)がインストールされているので、それを利用する機会が多くなってきました。備忘録も兼ねて、まとめておきます。

# 環境

- ホスト
    - MacBook Pro (16インチ, 2019)
        - macOS Monterey 12.2.1
    - Docker Desktop 4.5.0
    - PHP 8.1.3
    - Composer 2.2.7
- ゲスト
    - Laravel Sail
        - PHP 8.1.3
        - node.js 16.4.0
        - MySQL 8.0.x

# 準備

## Laravelのインストール

自分はComposerでインストールするのが好きなので、以下のようにインストールします。laravel-cliが好きな方はそちらで。

```terminal
composer create-project laravel/laravel laravel-sail-sample
```

## Laravel Sailの準備

すでにLaravel Sailはインストール済みなので、作成したLaravelのプロジェクトルートで以下のコマンドを実行します。一緒にどのサービスをインストールするか聞かれるので、ここでは`0 (mysql)`を選択します。例えばmysqlとmailhogをインストールする場合は`0, 7`と入力すればOKです。

```terminal
php artisan sail:install

 Which services would you like to install? [mysql]:
  [0] mysql
  [1] pgsql
  [2] mariadb
  [3] redis
  [4] memcached
  [5] meilisearch
  [6] minio
  [7] mailhog
  [8] selenium
 > 0

Sail scaffolding installed successfully.
```

プロジェクトルートに`docker-compose.yml`が以下のような作成されているはずです。

```yaml:docker-compose.yml
# For more information: https://laravel.com/docs/sail
version: '3'
services:
    laravel.test:
        build:
            context: ./vendor/laravel/sail/runtimes/8.1
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-8.1/app
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '${APP_PORT:-80}:80'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
            XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
            XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
        depends_on:
            - mysql
    mysql:
        image: 'mysql/mysql-server:8.0'
        ports:
            - '${FORWARD_DB_PORT:-3306}:3306'
        environment:
            MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ROOT_HOST: "%"
            MYSQL_DATABASE: '${DB_DATABASE}'
            MYSQL_USER: '${DB_USERNAME}'
            MYSQL_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ALLOW_EMPTY_PASSWORD: 1
        volumes:
            - 'sail-mysql:/var/lib/mysql'
        networks:
            - sail
        healthcheck:
            test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
            retries: 3
            timeout: 5s
networks:
    sail:
        driver: bridge
volumes:
    sail-mysql:
        driver: local
```

これで準備は完了です。

## Laravel Sailの利用のための一手間

Laravel Sailの実行ファイルはプロジェクトルート以下の`./vendor/bin/sail`になります。例えば、Laravel Sailで実行環境を立ち上げる際は、以下のように実行します。

```terminal
./vendor/bin/sail up
```

これを毎回打つのは面倒なので、zshやbashのエイリアスを追加します。私はmacOS標準のzshを使っているので、`~/.zshrc`に以下の行を追加しました。

```zsh:~/.zshrc
alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'
```

`~/.zshrc`に行を追加したら、以下を実行してzshを再起動しておきます。

```terminal
exec $SHELL -l
```

こうすることで、先ほどの実行環境立ち上げのコマンドは、以下のように短縮されます。

```terminal
sail up
```

## Laravel Sailの利用

### 1. 起動その１

以下のコマンドで起動します。この場合、終了は`Ctrl+C`です。

```terminal
sail up
```

標準では http://localhost/ でLaravelの標準のウェルカムページが立ち上がっているはずです。最初のup時はDockerイメージのPULLや準備のため3〜5分ほど完全に起動するまでに時間がかかります。

### 2. 起動その２

以下のコマンドでバックグラウンド起動します。この場合、終了は`3. 終了`の手順です。

```terminal
sail up -d
```

### 3. 終了

```terminal
sail stop
```

### 4. composerコマンド

composerは`sail composer`で起動します。以下はバージョンを表示した例です。

```terminal
sail composer --version
Composer version 2.2.7 2022-02-25 11:12:27
```

### 5. artisanコマンド

Laravelのartisanコマンドは`php artisan ...`と入力していましたが以下のように実行します。以下はテストを実行した例です。

```terminal
sail artisan test

   PASS  Tests\Unit\ExampleTest
  ✓ that true is true

   PASS  Tests\Feature\ExampleTest
  ✓ the application returns a successful response

  Tests:  2 passed
  Time:   0.49s
```

### 6. npmコマンド

ホストにnode.jsがインストールされていなくても、Laravel SailのDockerイメージ内にインストール済みですぐ利用出来ます。以下は`npm install`を実行した例です。

```terminal
sail npm install
```

このように`sail ${FOO} ...`とすれば、今まで使っていたコマンドが利用出来る事が分かります。

# まとめ

時前のdocker-compose.ymlをDockerfileを準備して、色々と時間がかかっていた事を考えると、サクッとできてしまうのはありがたいです。この環境を使って、Laravel Inertiaについて次は書いてみたいなと考えています。