DockerでPHP 8.4/Nginx + Node 22 + MySQL環境を構築する方法

# 概要
チーム開発で重要なのは、全員が同じ環境で作業できることです。本記事では、Dockerを活用して、PHP 8.4、Nginx、Node.js 22、MySQLを連携させた統一開発環境を構築する方法を解説します。Docker Composeを使用して、環境構築を効率化し、Laravelやフロントエンドの実行に最適なベース環境を整えます。

# 目的
### 開発環境の統一

- チーム開発において、全員が同じ環境で開発を進めるための基盤を構築すること。
- 各メンバーのローカル環境やOSに依存しない、一貫した開発環境を提供。

### 最新の技術スタックで効率的な開発を実現

- PHP 8.4やNode.js 22などの最新バージョンを使用し、モダンなアプリケーションを開発する。
- 最新のMySQLを組み合わせて、バックエンドとデータベースの効率的な連携を確立。

### コンテナ化によるスムーズなプロジェクトセットアップ

- 新しいメンバーが簡単に開発環境を構築できるようにする。
- セットアップの時間を削減し、即座に開発に取り掛かれる環境を提供。

### 開発と本番環境のギャップを解消

- Dockerを使用することで、本番環境とほぼ同じ環境での開発を実現。
- 環境差異による動作不具合を防ぎ、よりスムーズなデプロイを可能に。

### LaravelやVue.jsを利用したプロジェクトの基盤構築

- LaravelやVue.jsを含むモダンなアプリケーション開発のために、必要なバックエンド・フロントエンドの基盤を提供。
- 特にPHPとNode.jsを組み合わせることで、フルスタック開発を効率化。

# 前提条件
1. **Macを使用していること**
   - 本記事はMac環境を前提に手順を記載しています。他のOSをご利用の場合、適宜読み替えてください。(WindowsだとWSL想定)
2. **DockerとDocker Composeがインストールされていること**
   - Docker DesktopまたはDocker Engineがローカルマシンにインストールされている必要があります。
   - Docker Composeのバージョンが最新であることを確認してください。なるだけ現在最新のミドルウェアのコンテナで作成したい。

# 具体的な手順
## 構成
Dockerを使ってPHP、Node.js、MySQLの開発環境を構築します。最終的に、`src`ディレクトリ（アプリケーションのコードを配置）を`web`（バックエンド）と`node`（フロントエンド）のコンテナにマウントし、サーバーを起動します。
```
rootdir
  ├─ docker
  │    ├─ backend
  │    │   ├─ default.conf
  │    │   └─ Dockerfile
  │    ├─ db
  │    |   └─ my.cnf
  │    ├─ frontend
  │    │   └─ Dockerfile
  │    └─ docker-compose.yml
  └─ src
       └─ laravel11+vue3+typescript+inertiaを置く予定
```

## docker共通部分
#### **`rootdir/docker/docker-compose.yml`**
この設定ファイルでは、以下を実現します：
- **バックエンド（web）**: ポート80で公開（`localhost`にポート番号をつけたくないため）。
- **フロントエンド（node）**: Viteサーバーのデフォルトポート（5173）で公開。
- **共通**: `src`ディレクトリをコンテナ内にマウント。

```docker-compose.yml
version: '3.9'

services:
  backend:
    build:
      context: ./backend
    container_name: backend-container
    volumes:
      - ../src:/var/www/html
    ports:
      - "80:80"
    depends_on:
      - db

  frontend:
    build:
      context: ./frontend
    container_name: frontend-container
    working_dir: /var/www/html
    ports:
      - "5173:5173"
    volumes:
      - ../src:/var/www/html

  db:
    image: mysql:latest
    container_name: db-container
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: laravel
      MYSQL_USER: laravel
      MYSQL_PASSWORD: laravel
    volumes:
      - db_data:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/my.cnf

volumes:
  db_data:

```
## backend
#### **`rootdir/backend/default.conf`**
Nginxの設定：
- Laravelの/publicディレクトリをドキュメントルートとして指定。
- PHPリクエストをphp-fpmに転送。
```default.conf
server {
    listen 80;
    server_name localhost;

    root /var/www/html/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_index index.php;
    }

    location ~ /\.ht {
        deny all;
    }
}
```

#### **`rootdir/backend/Dockerfile`**
PHPコンテナの設定：

- 必要なライブラリやツールをインストール。
- Nginxの設定ファイルを配置し、php-fpmとNginxを実行。
```Dockerfile
FROM php:8.4-fpm

RUN apt-get update && apt-get install -y \
    nginx \
    procps \
    curl \
    zip \
    unzip \
    git \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    libzip-dev \
    && docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

COPY default.conf /etc/nginx/conf.d/default.conf

WORKDIR /var/www/html

CMD ["sh", "-c", "php-fpm & nginx -g 'daemon off;'"]
```

## db
#### **`rootdir/db/my.cnf`**
MySQLの設定：
- デフォルトのSQLモードを変更し、開発環境向けの設定を適用。
```my.cnf
[mysqld]
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
```

## frontend
#### **`rootdir/frontend/Dockerfile`**
Node.jsコンテナの設定：
- 必要なツールをインストール。
- コンテナ起動時にnpm installとnpm run devを実行。
```Dockerfile
FROM node:22

WORKDIR /var/www/html

RUN apt-get update && apt-get install -y \
    git \
    && apt-get clean

CMD ["sh", "-c", "npm install && npm run dev"]
```

## ポイント
- 共通ボリュームのマウント: srcディレクトリをバックエンド（PHP）とフロントエンド（Node.js）のコンテナにマウントすることで、ファイルの変更が即座に反映されます。
- シンプルなプロセス管理: 必要最低限のインストールと設定で軽量なコンテナ構成を実現。

これで、効率的な開発環境が整います！ 

# 確認
ここまでの構築が正しく動作するか確認します。  
**注意**: `src`にLaravelやVueのプロジェクトがまだインストールされていない場合、この手順をスキップすると動作しません。  
LaravelやVueのインストール後にエラーが発生すると、切り分けが難しくなるため、まずはテスト的なファイルを作成して動作確認を行います。


```
rootdir
  ├─ docker
  │    └─ 省略
  └─ src
       ├─ public
       |     └─ index.php
       ├─ package.json
       └─ server.js
```

以下をコピペして、それぞれのファイルを作成してください。
#### **`rootdir/src/public/index.php`**
```index.php
<?php
echo "Docker PHP web service is running!";

```

#### **`rootdir/src/package.json`**
```package.json
{
    "name": "docker-test",
    "version": "1.0.0",
    "scripts": {
        "start": "node server.js",
        "dev": "node server.js"
    }
}
```
#### **`rootdir/src/server.js`**
```server.js
const http = require("http");

const server = http.createServer((req, res) => {
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.end("Docker Node.js service is running!");
});

server.listen(5173, () => {
    console.log("Server running at http://localhost:5173/");
});
```

## コンテナ起動
以下のコマンドを実行して、コンテナを起動します。
```
$ cd docker
$ docker-compose up -d --build
```

起動が成功すると、以下のような出力が表示されます：
```
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
Creating node-container  ... done
Creating mysql-container ... done
Creating web-container   ... done
```
## コンテナ状態の確認
以下のコマンドで、3つのコンテナが正常に起動しているか確認します。
```
$ docker ps
```
出力例：
```
CONTAINER ID   IMAGE             COMMAND                  CREATED         STATUS         PORTS                               NAMES
627c292091eb   docker_backend    "docker-php-entrypoi…"   8 minutes ago   Up 8 minutes   0.0.0.0:80->80/tcp, 9000/tcp        backend-container
e904c72e9ecc   docker_frontend   "docker-entrypoint.s…"   8 minutes ago   Up 8 minutes   0.0.0.0:5173->5173/tcp              frontend-container
39307e73f8c9   mysql:latest      "docker-entrypoint.s…"   8 minutes ago   Up 8 minutes   0.0.0.0:3306->3306/tcp, 33060/tcp   db-container
```

## トラブルシューティング
### コンテナが起動していない場合
以下のコマンドで、対象のコンテナのログを確認します。
```
$ docker logs <コンテナ名>
```
#### 例: フロントエンドコンテナのログ確認
```
$ docker logs frontend-container  

up to date, audited 1 package in 518ms

found 0 vulnerabilities
npm error Missing script: "dev"
npm error
npm error To see a list of scripts, run:
npm error   npm run
npm error A complete log of this run can be found in: /root/.npm/_logs/2025-12-29T07_56_38_624Z-debug-0.log
```
エラーが出力された場合、問題箇所を修正します。

## コンテナを再起動
修正後、以下のコマンドで全てのコンテナを停止し、再度起動します。
```
$ docker-compose down
$ docker-compose up -d --build
```

## 表示結果
#### bakcend
[http://localhost](http://localhost) にアクセスして、以下のメッセージが表示されれば成功です。
![スクリーンショット 2025-01-02 17.04.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1032988/60d3fd9b-e023-71ae-89f1-842d41dc1dad.png)


#### frontend
[http://localhost:5173](http://localhost:5173) にアクセスして、以下のメッセージが表示されれば成功です。
![スクリーンショット 2025-01-02 17.06.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1032988/e8d2cdff-52c0-a12f-2b98-1d5b8829bc84.png)

# まとめ

ここまでで、Dockerを使ったPHP、Node.js、MySQLの統一開発環境を構築し、動作確認までを行いました。この手順を通じて、以下のポイントを押さえることができました：

1. **Dockerを利用した一貫した環境構築**  
   - PHP 8.4、Node.js 22、MySQLといった最新技術を簡単に連携。
   - チーム全体で同じ環境を共有し、開発効率を向上。

2. **コンテナごとの役割分担**  
   - バックエンド（web）とフロントエンド（node）、データベース（db）を個別のコンテナで管理することで、柔軟性を確保。

3. **動作確認の重要性**  
   - LaravelやVue.jsをインストールする前に、最小限の構成でコンテナが正常動作することを確認。
   - エラー発生時の切り分けを容易にするプロセスを学習。

Dockerを使うことで、開発と本番環境のギャップを減らし、安定した開発基盤を構築できます。この基盤があれば、新しいメンバーがすぐに作業を始められる環境を提供でき、チーム全体の生産性を向上させることができます。

---

### 次の記事の紹介

ここまでで基盤となるDocker環境が整いました。次の記事では、実際に`Laravel 11`と`Vue 3`、`TypeScript`、`Inertia.js`を使ったモダンなフルスタック開発環境を構築していきます。

次の記事はこちら：
[Laravel 11 + Inertia.js + Vue 3 + TypeScriptでモダンなフルスタック環境を構築](#)  

この記事では、以下のポイントを解説予定です：
- LaravelとVueのインストール
- TypeScriptによる型安全なフロントエンド開発
- Inertia.jsを使ったシームレスなバックエンド連携

引き続き良かったら読んでください！

### 関連記事
- [Laravel + Vue3 チーム開発を効率化！統一環境構築と品質向上の完全ガイド](https://qiita.com/ukei2021/items/4b2f047c72dd17c571c7)
- [Laravel 11 + Inertia.js + Vue 3 + TypeScriptでモダンなフルスタック環境を構築](https://qiita.com/ukei2021/items/ca36f47975e5fc5ff16e)
- [Laravel 11 + Vue 3プロジェクトにSassとBootstrap 5を導入する方法](https://qiita.com/ukei2021/items/2a0916ffc9c6ef900cb4)
- [Laravelでテストコード込みのサービス・リポジトリパターンを実装する方法](https://qiita.com/ukei2021/items/53d3776f580cfd3a074b)
- [DevContainerを使いVSCodeでPHPStan・ESLint・TypeScriptを統合して静的解析をエラー検知する方法](https://qiita.com/ukei2021/items/d3a91b0a34188529b6f6)
- [Gitコミット時に自動チェック！HuskyでESLint・PHPStan・ユニットテストを効率化する方法](https://qiita.com/ukei2021/items/592b50cbe04aaeae575f)