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つのプロジェクトで簡単に作りたい場合は下記の記事がおすすめ!

この記事をシェアする