Laravelの複数プロジェクト開発をするとき、プロジェクトごとにphp artisan serveしたり、あるいはdocker-compose down,upしている方、めんどくさいですよね?
私もM1 Macになってからそんな環境になっていたため、「めんどくさい!1回docker-compose upしたら全環境動いてほしい」と思っていました。
そしてようやく、そんな環境とはおさらばし、新たなdocker環境を構築しました。今回は、複数のLaravelプロジェクトを同時に動かす方法について紹介します。
環境
MacBook Pro(14インチ、2021)macOS Monterey 12.3.1
Docker Version4.8.1
Laravel9
PHP8.1
mysql8
ディレクトリ構成
% tree
.
├── docker-compose.yml
├── infra
│ ├── app
│ │ ├── Dockerfile
│ │ └── php.ini
│ ├── db
│ │ ├── Dockerfile
│ │ └── my.conf
│ └── web
│ ├── Dockerfile
│ └── default.conf
└── projects
├── project_1
└── project_2
一般的なWeb3層のコンテナ構成です。
appにアプリケーションコンテナ
dbにDBコンテナ
webにwebサーバーコンテナ
そして、projectsディレクトリの中に各プロジェクトが格納されます。
手順
docker-compose.yml
まずは作業ルートにdocker-compose.ymlファイルを作成し、以下のように記述してください。
version: "3.9"
services:
# [プロジェクトごとに設定]webアプリケーションのコンテナ
project_1:
build:
context: .
dockerfile: ./infra/app/Dockerfile
volumes:
- ./projects/project_1/:/app/project_1
project_2:
build:
context: .
dockerfile: ./infra/app/Dockerfile
volumes:
- ./projects/project_2/:/app/project_2
# [プロジェクト共通]webサーバーのコンテナ(プロジェクトごとにports,depends_on,volumesを設定)
web:
build:
context: .
dockerfile: ./infra/web/Dockerfile
ports:
- "8081:8081"
- "8082:8082"
depends_on:
- project_1
- project_2
volumes:
- ./projects/project_1/:/app/project_1
- ./projects/project_2/:/app/project_2
# [プロジェクト共通]dbサーバーのコンテナ
db:
build:
context: .
dockerfile: ./infra/db/Dockerfile
ports:
- "3306:3306"
environment:
MYSQL_DATABASE: database
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
TZ: 'Asia/Tokyo'
volumes:
- mysql-volume:/var/lib/mysql
volumes:
mysql-volume:
webのportsには使われていない番号を記入しましょう。
アプリケーションコンテナ
次にアプリケーションのコンテナの設定になります。
appディレクトリにDockerfileファイルを作成し、以下のように記述してください。
FROM php:8.1-fpm
ENV TZ Asia/Tokyo
RUN apt-get update && \
apt-get install -y git unzip libzip-dev libicu-dev libonig-dev nodejs npm libfreetype6-dev libjpeg62-turbo-dev libpng-dev && \
docker-php-ext-install intl pdo_mysql zip bcmath gd
COPY ./infra/app/php.ini /usr/local/etc/php/php.ini
COPY --from=composer /usr/bin/composer /usr/bin/composer
# コンテナ内で使えるalias
RUN echo "alias ..='cd ..'" >> ~/.bashrc && \
echo "alias ...='cd ../..'" >> ~/.bashrc && \
echo "alias ll='ls -l'" >> ~/.bashrc && \
echo "alias lla='ls -la'" >> ~/.bashrc && \
echo "alias ..='cd ..'" >> ~/.bashrc && \
echo "alias ...='cd ../..'" >> ~/.bashrc && \
# laravel
echo "alias art='php artisan'" >> ~/.bashrc && \
echo "alias arts='art serve'" >> ~/.bashrc && \
echo "alias artr='art route:list'" >> ~/.bashrc && \
echo "alias migrate='art migrate'" >> ~/.bashrc && \
echo "alias seed='art db:seed'" >> ~/.bashrc && \
echo "alias rollback='art migrate:rollback'" >> ~/.bashrc && \
echo "alias fresh='art migrate:fresh'" >> ~/.bashrc && \
echo "alias cc='php artisan config:clear && php artisan cache:clear && php artisan view:clear'" >> ~/.bashrc && \
echo "alias cca='php artisan config:clear && php artisan cache:clear && php artisan view:clear && php artisan config:cache'" >> ~/.bashrc && \
echo "alias test='./vendor/bin/phpunit --testdox'" >> ~/.bashrc && \
# git
echo "alias gb='git branch'" >> ~/.bashrc && \
echo "alias gc='git checkout'" >> ~/.bashrc && \
echo "alias gcd='gc develop'" >> ~/.bashrc && \
echo "alias gcr='gc release'" >> ~/.bashrc && \
echo "alias gcs='gc stage'" >> ~/.bashrc && \
echo "alias gs='git status'" >> ~/.bashrc && \
echo "alias gp='git pull'" >> ~/.bashrc
WORKDIR /app
PHPのパッケージやnode、npmなどをインストールする記述やcomposerの導入、Laravelで使えるalias などが定義されています。
次にphp.iniを作成します。
appディレクトリにphp.iniファイルを作成し、以下のように記述してください。
zend.exception_ignore_args = off
expose_php = on
max_execution_time = 30
max_input_vars = 1000
upload_max_filesize = 64M
post_max_size = 128M
memory_limit = 256M
error_reporting = E_ALL
display_errors = on
display_startup_errors = on
log_errors = on
error_log = /var/log/php/php-error.log
default_charset = UTF-8
[Date]
date.timezone = Asia/Tokyo
[mysqlnd]
mysqlnd.collect_memory_statistics = on
[Assertion]
zend.assertions = 1
[mbstring]
mbstring.language = Japanese
Webサーバーコンテナ
次にwebサーバーのコンテナを作成します。今回はnginxを利用します。
webディレクトリにDockerfileファイルを作成し、以下のように記述してください。
FROM nginx:1.20-alpine
ENV TZ Asia/Tokyo
COPY ./infra/web/default.conf /etc/nginx/conf.d/default.conf
nginxの設定ファイルを作成します。
webディレクトリにdefault.confファイルを作成し、以下のように記述してください。
# ルール
# ①プロジェクトごとにserverを作成する
# ②listenにはポート番号を入れユニークな数字にする
# ③server_name,root,fastcgi_passにプロジェクト名を入れる
server {
listen 8081;
server_name project_1.com;
root /app/project_1/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass project_1:9000;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
server {
listen 8082;
server_name project_2.com;
root /app/project_2/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass project_2:9000;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
まず、大枠のserverを作成します。こちらはプロジェクトの数分コピペで作成してください。
続いてlistenには利用するポート番号を指定します。こちらはdocker-compose.ymlのwebのportsに記載したポート番号をそれぞれ定義します。
そして、server_name,root,fastcgi_passに各プロジェクト名を入れてください。プロジェクト名はdocker-compose.ymlファイルに記述したものと同じである必要があります。
DBコンテナ
そして最後にDBのコンテナです。こちらは簡単です。
dbディレクトリにDockerfileとmy.confファイルを作成し、それぞれ以下のように記述してください。
Dockerfile
FROM mysql:8.0
COPY ./infra/db/my.conf /etc/my.conf
my.conf
[mysqld]
# character
character_set_server = utf8mb4
collation_server = utf8mb4_0900_ai_ci
# timezone
default-time-zone = SYSTEM
log_timestamps = SYSTEM
# Error Log
log-error = mysql-error.log
# Slow Query Log
slow_query_log = 1
slow_query_log_file = mysql-slow.log
long_query_time = 1.0
log_queries_not_using_indexes = 0
# General Log
general_log = 1
general_log_file = mysql-general.log
[mysql]
default-character-set = utf8mb4
[client]
default-character-set = utf8mb4
プロジェクトの作成
ここまでできたらprojectsディレクトリに各プロジェクトのディレクトリを作成します。
まずはコンテナを立ち上げましょう。
$ docker-compose up -d
既存のプロジェクトがある場合
各ディレクトリにcloneしてください。cloneしたらプロジェクトごとに下記のコマンドを実行してください。
#project_1でcomposer install
$ docker-compose exec -w /app/project_1 project_1 composer install
#project_2でcomposer install
$ docker-compose exec -w /app/project_2 project_2 composer install
うまく動きましたか?
既存のプロジェクトによってはPHPのモジュールが足りずにエラーとなる場合もあります。その場合はappのDockerfile内で必要なモジュールをインストールしてみてください。PHPのバージョンなどにもご注意ください。
新規でLaravelプロジェクトを作る場合
特にディレクトリは作らなくて大丈夫です。プロジェクトごとに下記のコマンドを実行してください。
#project_1にLaravelプロジェクトを導入
$ docker-compose exec -w /app/project_1 project_1 composer create-project laravel/laravel .
#project_2にLaravelプロジェクトを導入
$ docker-compose exec -w /app/project_2 project_2 composer create-project laravel/laravel .
これで環境構築完了です。
localhost:8081とlocalhost:8082にアクセスしてみましょう。
おまけ
コンテナへのアクセス
各コンテナへは以下のコマンドで入ることができます。
# appコンテナ
$ docker-compose exec project_1 bash
$ docker-compose exec project_2 bash
# webコンテナ
$ docker-compose exec web sh
# dbコンテナ
$ docker-compose exec db bash
出るときはCtrl + Dもしくはexitコマンドで出れます。
aliasの設定
localhost:8081とlocalhost:8082でそれぞれプロジェクトが動くようになりましたが、プロジェクトが多いとポート番号を覚えていられなくなりそうです。
そんな時、ブラウザで画面を開く場合はコマンドで開くのがおすすめです。
お使いのPC(コンテナ内ではなくホスト側で)の~/.bashrcや~/.zshrcなどのファイルに以下のように記述しましょう。
alias pro1o='open http://localhost:8081'
alias pro2o='open http://localhost:8082'
保存したら、source ~/.zshrc(または source ~/.bashrc)を実行しaliasを使えるようにします。
この状態でターミナルでpro1oと打ってみてください。
コマンドでブラウザを開くことでポート番号を覚えなくても手軽にサイトを開くことができます。
DB接続
DBコンテナに入り各プロジェクトのデータベースを作成します。
# dbコンテナに入る
$ docker-compose exec db bash
$ mysql -u root -p
$ #パスワードを入力し、enter(パスワードはdocker-compose.ymlのMYSQL_ROOT_PASSWORD)
$ create database project1_db; # project1_dbは任意な名前にする
$ create database project2_db; # project2_dbは任意な名前にする
あとは各プロジェクトコンテナ内の.envに設定情報を書きます。
#project1での記載例
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=project1_db
DB_USERNAME=user
DB_PASSWORD=password
マイグレーションしてみて問題なければOKです。
$ docker-compose exec -w /app/project_1 project_1 php artisan migrate
まとめ
今回の構成ではwebサーバーとdbサーバーのコンテナは共通化し、アプリケーションコンテナはそれぞれ存在する形で作成しました。
M1 Macを使う前はLaradock環境でシェルのコマンド1つ打てば自動でgit cloneから環境構築できる形だったので、それと比べるとまだまだ改善の余地はありそうです。
今後もさらに改善し、磨きをかけていきたいと思います!
関連記事
シンプルに1つのプロジェクトで簡単に作りたい場合は下記の記事がおすすめ!