Docker で Laravel の環境構築をしました
やりたい事
- Laravel の Eloquent の機能を色々試したい
- 単体テスト形式でコードを書いて試したい
- テスト実行時には、開発用 DB とは別にテスト用の DB を用意したい
Eloquent を勉強するため、まずは検証環境を用意する事から着手しました。 その時の過程やハマったポイント等をまとめました。
環境情報
- Docker version 18.09.2
- docker-compose version 1.23.2
アプリ(Laravel)の環境構築
こちらの記事を参考にさせて頂きました。構成はほぼ同じです。
ただ、PHP のバージョンは 7.3 で作成したかったため、一部変更して実行しました。
まずはアプリのみを構築(Laravel をインストールするまで)
- docker-compose.yml
version: '3' services: php: container_name: php build: ./docker/php volumes: - ./server:/var/www nginx: image: nginx container_name: nginx ports: - 80:80 volumes: - ./server:/var/www - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - php # db に関するものはいったん削除しています。(後で追加)
docker/php/Dockerfile を変更
PHP 7.3 を使いため、イメージ指定を変更しました。
また、apt-get でインストールするものにlibzip-dev
を追加しました。(ハマったポイントその1)
- docker/php/Dockerfile
FROM php:7.3-fpm # ← 7.2-fpm から変更 COPY php.ini /usr/local/etc/php/ RUN apt-get update \ # ↓ libzip-dev を追加 && apt-get install -y zlib1g-dev libzip-dev mysql-client \ && docker-php-ext-install zip pdo_mysql # Composer install RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" RUN php -r "if (hash_file('sha384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" 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"
後は、参考サイト通りに Laravel をインストールし、動作確認(Laravel と書かれたページが表示)まで実施します。
※ 次に行く前にいったん環境を停止しておきます。
$ docker-compose down
DB の環境構築
開発用 DB とは別にテスト用 DB を作成するため、また、テスト実行時にはちゃんとテスト用 DB へ向ける必要があるため、以下のサイトを参考にして進めました。
以下のルールで構築します。
- 開発用 DB 名は
study
- テスト用 DB 名
study_testing
DB コンテナの定義を追記
MySQL は root ユーザーで運用したいため、MYSQL_USER
,MYSQL_PASSWORD
を削除しました。(※ 他ユーザーへの権限付与等の手間を省きました。手を抜きました。。。)
- docker-compose.yml
version: '3' services: php: 〜 略 ~ nginx: 〜 略 〜 db: image: mysql:5.7 container_name: db-host environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: study # DB 名を変更 # MYSQL_USER, MYSQL_PASSWORD は削除 TZ: 'Asia/Tokyo' # ↓ utf8mb4_general_ci に変更 command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci volumes: - ./docker/db/data:/var/lib/mysql - ./docker/db/my.conf:/etc/mysql/conf.d/my.cnf - ./docker/db/sql:/docker-entrypoint-initdb.d ports: - 3306:3306
server/config/database.php を変更
テスト用 DB への接続情報を追記します。
- server/config/database.php
<?php 'connections' => [ 'sqlite' => [ 'driver' => 'sqlite', 'database' => env('DB_DATABASE', database_path('database.sqlite')), 'prefix' => '', 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), ], 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_general_ci', // ← utf8mb4_general_ci に変更 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), ]) : [], ], // ↑ の 'mysql' をキーとするものをコピーして、キーを変更します。 'mysql_testing' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_general_ci', 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), ]) : [], ],
server/.env を変更
DB_HOST が 127.0.0.1
だったので、DB のコンテナ名を指定します。(※ ハマったポイントその2)
- server/.env
〜略〜 DB_CONNECTION=mysql DB_HOST=db-host # DB コンテナの名前を指定 DB_PORT=3306 DB_DATABASE=study DB_USERNAME=root DB_PASSWORD=root 〜略〜
server/.env.testing ファイルを作成
server/.env ファイルをコピーして作成します。テスト時はstudy_testing
を見にいくようにします。
- server/.env.testing
〜略〜 DB_CONNECTION=mysql_testing # ← テスト用の方を見るように指定します。 DB_HOST=db-host DB_PORT=3306 DB_DATABASE=study_testing # ← テスト用 DB を見るように指定します。 DB_USERNAME=root DB_PASSWORD=root 〜略〜
テスト用 DB 作成 SQL を用意(※ハマったポイントその3)
コンテナ起動時にテスト用 DB が作成されるように SQL ファイルを以下の場所に作成します。
CREATE DATABASE IF NOT EXISTS study_testing CHARACTER SET utf8mb4;
コンテナを起動する
$ docker-compose up -d
これで、ローカルから MySQL Workbench 等を使って DB コンテナへアクセスすれば、study
と study_testing
という DB が作成されている事が確認出来るかと思います。
マイグレーション
まだ各 DB の中身は空っぽなので、Laravel のマイグレーションを利用してテーブルを作ります。
アプリ(Laravel)のコンテナに入る
以下のコマンドでコンテナに入ります。
$ docker-compose exec php bash
開発用 DB に対してマイグレーション
$ php artisan migrate
これで DB study
内に users テーブル等が作成されます。
テスト用 DB に対してマイグレーション
--env=testing
を指定する事で、server/.env.testing
ファイルを読み込んで実行する事が出来ます。
$ php artisan migrate --env=testing
これで、開発用 DB と同様に、study_testing
にもテーブルが作成されます。
以上で、おおかた環境を整える事が出来ました。
Eloquent 10 本ノックの本編は次回に書きたいと思います!
ハマった事
ハマったポイントその1
$ docker-compose up -d
実行時にエラー
最初、libzip-dev
は追記せずにイメージだけを変更して、
$ docker-compose up -d
を実行したところ、以下のようなエラーが出ました。
〜略〜 checking for pkg-config... /usr/bin/pkg-config checking for libzip... not found configure: error: Please reinstall the libzip distribution ERROR: Service 'php' failed to build: The command '/bin/sh -c apt-get update && apt-get install -y zlib1g-dev mysql-client && docker-php-ext-install zip pdo_mysql' returned a non-zero code: 1
PHP 7.3 では、このlibzip-dev
が必要なようですが、そのソースまでは辿り着けませんでした。。
ハマったポイントその2
$ php artisan migrate
でSQLSTATE[HY000] [2002] Connection refused
エラー内容の詳細
$ php artisan migrate Illuminate\Database\QueryException : SQLSTATE[HY000] [2002] Connection refused (SQL: select * from information_schema.tables where table_schema = database and table_name = migrations) at /var/www/vendor/laravel/framework/src/Illuminate/Database/Connection.php:664 660| // If an exception occurs when attempting to run a query, we'll format the error 661| // message to include the bindings with SQL, which will make this exception a 662| // lot more helpful to the developer instead of just the database's errors. 663| catch (Exception $e) { > 664| throw new QueryException( 665| $query, $this->prepareBindings($bindings), $e 666| ); 667| } 668| Exception trace: 1 PDOException::("SQLSTATE[HY000] [2002] Connection refused") /var/www/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:70 2 PDO::__construct("mysql:host=127.0.0.1;port=3306;dbname=database", "root", "root", []) /var/www/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:70 Please use the argument -v to see more details.
DB にアクセス出来ないよ、というエラーが発生しました。
この時、ローカルの MySQL Workbench からは接続が出来て、空っぽのstudy
データベースが見れる事を確認しました。
そのため、php コンテナから db-host コンテナへのアクセスする設定が何かしら足りないんじゃないかと疑いました。
そして、server/.env
ファイルを見ると、
DB_HOST=127.0.0.1
となっていたので、これを DB のコンテナ名 db-host
にする事で解決出来ました。
ハマったポイントその3
./docker/db/sql
に置いた SQL ファイルが実行されない問題
テスト用の DB を用意する前に Laravel の環境を構築していたわけですが、その際にはもちろん DB が構築されており、
docker/db/data
にデータが作成されている状態でした。
以下の参考サイトにもあるように、データが永続化されている場合には、初めての起動時にしか ./docker/db/sql
に置いた SQL は実行されないようです。
- 参考サイト
開発段階では、データを永続化したいですし、
今更ではありますが、開発用 DB とテスト用 DB を分けて考える場合、同一コンテナではなくて別々のコンテナを用意してあげればよかったのかもしれません。。
まとめ
- やはり環境構築は骨が折れます。。(慣れるしかないかな!?)
- Docker 使ってるおかげでいくらでも作って、消してが試せる!(ローカルが汚れる心配なし!)
- 次回は、いよいよ Eloquent を触って行きます!