laravelでsailを使って環境構築!DBに接続できない問題の解決(laravel10)
今まであまりsailを使ってこなかったので、使ってメモでも残しておこうと思う。今回はlaravel10で試してます。
curlでインストールする方法はこちら
プロジェクト作成は、公式ドキュメントの「インストール」ページで、どぉーんとcurlによる以下の手順が紹介されています。Docker Desktopがインストールされている状態なら、以下のコマンドで簡単に環境が構築できるようです。
$ curl -s "https://laravel.build/example-app" | bash
-> laravel, mysql, redis, mailpit, meilisearch, seleniumのコンテナが自動生成された
redis, mailpit, meilisearch, seleniumあたりは必要な時にインストールしたい。そんな時は、下記のように指定することも出来るみたい。
$ curl -s "https://laravel.build/example-app?with=mysql,redis" | bash
-> laravel, mysql, redisのコンテナが自動生成された
しかし、プロジェクト作成時に、「with句に何の文字列が使えたっけ?」みたいな手間があるので、個人的にはこちらは使わない。普通にcomposerコマンドで作成したプロジェクトに、sailを導入する流れで実行してみる。
既存のプロジェクトにsailを導入する方法
まずは普通にプロジェクトを作成
$ composer create-project laravel/laravel example-app
sailを導入する
$ cd example-app
$ composer require laravel/sail --dev
$ 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] mailpit
[8] selenium
[9] soketi
> 0,3
必要なサービスを選んで入力してEnter
起動する
$ ./vendor/bin/sail up
# バックグラウンドで実行したい場合
## 起動
$ ./vendor/bin/sail up -d
## 停止
$ ./vendor/bin/sail down
http://localhost/にアクセスすると、welcomeページが表示できるようになりました。
migrateなどのartisanコマンドは?
sailを使用する場合は、アプリケーションがdockerのコンテナ内で実行されることになるので、artisanコマンドやcomposerコマンドをコンテナ内で実行しなければならないケースが出てきます。
下記のコマンドで、実行することができます。一度コンテナに入って作業する必要はないんですね。ありがたい。
# PHP
$ ./vendor/bin/sail php --version
# artisanコマンド
$ ./vendor/bin/sail artisan migrate
# composerコマンド
$ ./vendor/bin/sail composer require xxxxxxxxxx
ちなみに(laravelの)コンテナに入りたい場合は、以下で入れるみたい。
$ ./vendor/bin/sail shell
しかし、このままartisanコマンドを実行しても失敗します。まさかのDB接続失敗です。えぇぇ・・・。まさかのですよね。実はココというよりDBの設定の話なのですが。
構築自体の話はmigrateが実行できれば終了なので、ここまでです。ここからはDBの注意点について、述べます。
【注意点】「sail:install」によるDB設定書き換えと実際に構築されるモノ
「sailを導入する」項目で実行した以下のコマンドがあります。
$ php artisan sail:install
このコマンドで実行される内容の一部を見てみます。
docker-compose.ymlの生成と.envファイルの書き換え
まず.envが自動で書き換えられます。ご覧ください。
# プロジェクト作成時のデフォルト.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
↓
# 「sail:install」によって自動で書き換えられた.env
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=sail
DB_PASSWORD=password
まず「DB_HOST」が書き換えられます。これは、laravelアプリのコンテナからmysqlコンテナに通信しにいこうとするので、問題ないでしょう。
さらに、「DB_USERNAME」「DB_PASSWORD」が修正されています。つまり、開発環境として、この設定で自動でユーザー作成して構築してくれるということ。うんうん、良いでしょう。
さて今度は、自動生成されるdocker-compose.ymlを見てみます。
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'
- './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
networks:
- sail
「environment」の項目を見てください。やはり、先程の「DB_USERNAME」「DB_PASSWORD」を使ってユーザー作成するよう自動設定してくれています。加えて言うと、「DB_DATABASE」を使ってDB作成してくれて、rootユーザーのパスワードにも、「DB_PASSWORD」を利用してくれているみたい。
構築さえたDBを確認してみると
コンテナに入ってみます。
$ docker-compose exec mysql bash
bash-4.4# mysql -uroot -p
→.envに書かれたパスワード「password」でログイン可能
さて、DBを閲覧してみます。
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| example_app |
| information_schema |
| mysql |
| performance_schema |
| sys |
| testing |
+--------------------+
6 rows in set (0.00 sec)
分かりますか?.envには、「DB_DATABASE=laravel」と記述してありますが、蓋を開けてみると、作成されていたDBはプロジェクト名である「example_app」でした。
DB名をexample_appにして接続してみると
1) laravelコンテナに入ってmysql接続
$ ./vendor/bin/sail shell
sail@fa8c589225bd:/var/www/html$ mysql -hmysql -usail -p example_app
→無事に接続できました。
2) .envのDB名を書き換えて、migrate実行
$ ./vendor/bin/sail artisan migrate
→無事に実行できました。
【愚痴】おいおい、だとすると!「sail:install」実行時にDB_DATABASEをなぜ書き換えないんだ・・
いやいやw 「DB_HOST」を書き換えて、「DB_USERNAME」を書き換えて、「DB_PASSWORD」を書き換えて、「DB_DATABASE」だけ書き換えないって・・・なんぞ!
完全にトラップです。
まとめ
sailで構築して開発をスタートできるのは、とても良いですね。ただし、sail使わなくても自分でコンテナ構築できないと、今回のようなトラップになかなか気づけないかもしれないですね。
なんのための自動構築なのか・・・w
ちなみにlaravel9で試してみた
laravel10がまだ浅いから故のバグかな・・と思い、laravel9を試してみました。なんと、laravel9では普通に「laravel」という名前でDBが作成されており、そのまま動作しました。バグかーーい。
それでは。