5
5
この記事誰得? 私しか得しないニッチな技術で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

Docker でチーム開発用の PHP 8.3 + Apache + Laravel 11 + MySQL 8 + phpMyAdmin 環境を構築

Last updated at Posted at 2024-06-28

また今度が来るまでに 5年かかったゾ。

対象読者

  • これまで XAMPP インストールして hosts 書いて httpd.conf に VirtualHost 書いてローカル開発環境を構築していたが、そろそろ Docker に移行したい私
  • 上記の工程を開発メンバー各自にも行なってもらっていて、今時 Docker じゃなくてゴメンと思っていた私
  • 他の Docker 環境構築記事のレベルが高すぎて理解できなかった私

動作確認環境

あらかじめ Docker Desktop のインストールを完了しておいてください。

Windows

  • Windows 10 Enterprise 22H2
  • Docker Desktop 4.31.1
    • Docker 26.1.4
    • Docker Compose v2.27.1-desktop.1

Mac

  • macOS Ventura 13.0.1
  • Docker Desktop 4.31.0
    • Docker 26.1.4
    • Docker Compose v2.27.1-desktop.1

構築内容

  • Apache 2.4.59 (Debian)
  • PHP 8.3.7
  • Composer Latest
  • MySQL 8.0.37
  • phpMyAdmin

ディレクトリ構造

以下のように案件リポジトリとして Git 管理する想定。

  .
  ├── app/
  │    └── laravel/
  ├── docker/
  │    ├── mysql/
  │    │    ├── data/
  │    │    │    └── .gitignore
  │    │    ├── initdb.d/
  │    │    │    └── initdb.sql
  │    │    ├── Dockerfile
  │    │    └── my.cnf
  │    ├── php/
  │    │    ├── Dockerfile
  │    │    └── php.ini
  │    └── phpmyadmin/
  │         ├── sessions/
  │         │    └── .gitignore
  │         └── Dockerfile
  ├── .git
  └── compose.yaml

サンプル
https://github.com/naente/tutorial-docker

ファイル詳細

compose.yaml
services:
  db:
    build: ./docker/mysql
    container_name: db-container
    volumes:
      - ./docker/mysql/data:/var/lib/mysql
      - ./docker/mysql/initdb.d:/docker-entrypoint-initdb.d
    environment:
      - MYSQL_ROOT_PASSWORD=mysql
      - MYSQL_DATABASE=database
      - MYSQL_USER=user
      - MYSQL_PASSWORD=password
      - TZ=Asia/Tokyo
    ports:
      - '3306:3306'
  app:
    build: ./docker/php
    container_name: app-container
    volumes:
      - ./docker/php/php.ini:/usr/local/etc/php/php.ini
      - ./app/laravel:/var/www
    ports:
      - '8080:80'
    depends_on:
      - db
  phpmyadmin:
    build: ./docker/phpmyadmin
    container_name: phpmyadmin-container
    volumes:
      - ./docker/phpmyadmin/sessions:/sessions
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=db
      - PMA_USER=root
      - PMA_PASSWORD=mysql
    ports:
      - '4040:80'
    depends_on:
      - db

db サービス

compose.yamldb サービスの volumes ではマウントを使用したホスト側へのデータ保存、初期データの投入を設定しています。
初期データの投入はお試しで書いたので、不要であれば割愛して問題ありません。


docker/mysql/data/.gitignore
*
!.gitignore

当該フォルダをあらかじめ Git 管理に含めておきたいので .gitignore を置きます。

docker/mysql/initdb.d
CREATE TABLE IF NOT EXISTS pet
(
    name VARCHAR(20),
    owner VARCHAR(20),
    species VARCHAR(20),
    sex CHAR(1),
    birth DATE,
    death DATE
);

INSERT INTO pet
VALUES ('Puffball', 'Diane', 'hamster', 'f', '1999-03-30', NULL);

初期データ投入のお試し用です。

docker/mysql/Dockerfile
FROM mysql:8.0.37

COPY ./my.cnf /etc/mysql/conf.d/my.cnf
RUN chmod 644 /etc/mysql/conf.d/my.cnf

Windows 環境の場合、マウントでパーミッション問題が発生するので Dockerfile の中で良い感じにしてやります。

参考:Docker で MySQL コンテナを作る方法

docker/mysql/my.cnf
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci

[mysql]
default-character-set = utf8mb4

[client]
default-character-set = utf8mb4

照合順序は信頼と実績の utf8mb4_general_ci を採用していますが、お好みでどうぞ。

参考:MySQL の utf8mb4 の文字照合順序まとめ

app サービス

Laravel の場合、ドキュメントルートの変更(下記 Dockerfile 参照)が必要です。その上で public と同階層のディレクトリおよびファイルもコンテナへ同期する(compose.yamlapp サービスの volumes 参照)必要があります。


docker/php/Dockerfile
FROM php:8.3.7-apache

# ドキュメントルートを変更
ENV APACHE_DOCUMENT_ROOT /var/www/public
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf

# パッケージインストール
RUN apt-get update && apt-get install -y \
    libicu-dev \
    libonig-dev \
    libzip-dev \
    zlib1g-dev \
    unzip \
    locales \
    vim \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Apache の rewrite_module を有効化
RUN a2enmod rewrite

# PHP のエクステンションをインストール
RUN docker-php-ext-install \
    # ctype \
    # curl \
    # dom \
    # fileinfo \
    # filter \
    # hash \
    intl \
    # json \
    # mbstring \
    # openssl \
    # pcre \
    # PDO \
    pdo_mysql \
    # pdo_sqlite \
    # session \
    # tokenizer \
    # xml \
    zip

# Composer インストール
COPY --from=composer /usr/bin/composer /usr/bin/composer

# コンテナログイン時のパス指定
WORKDIR /var/www

エクステンション関連はお好みで。
上記では Laravel 11 で必須要件となっている拡張と自分がよく使う CodeIgniter 4 で必須要件となっている拡張をインストールしています。
※コメントアウトは採用したコンテナイメージで標準インストールされており不要だったものです。

docker/php/php.ini
[Date]
date.timezone = Asia/Tokyo

[mbstring]
mbstring.language = Japanese

ここもお好みで。

phpmyadmin サービス

compose.yamlenvironment > PMA_HOST には接続するデータベースのサービス名、PMA_PASSWORD には接続するデータベースサービスの environment > MYSQL_ROOT_PASSWORD で定義された値を指定する。


docker/phpmyadmin/sessions/.gitignore
*
!.gitignore

当該フォルダをあらかじめ Git 管理に含めておきたいので .gitignore を置きます。

docker/phpmyadmin/Dockerfile
FROM phpmyadmin:apache

Docker 動作確認

現在のコンテナ稼働状況を確認

> docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

稼働中のコンテナが存在していないため、何も表示されません。

コンテナの作成とサービスの開始

> docker compose up -d

コンテナの稼働状況を確認します。

> docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS                               NAMES
227d617fbbfd   phpmyadmin   "/docker-entrypoint.…"   37 seconds ago   Up 24 seconds   0.0.0.0:4040->80/tcp                phpmyadmin-container
d33c7973bec6   app          "docker-php-entrypoi…"   37 seconds ago   Up 26 seconds   0.0.0.0:8080->80/tcp                app-container
b83d0a07dfb0   db           "docker-entrypoint.s…"   39 seconds ago   Up 30 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp   db-container

補足

Mac の場合、以下のようなエラーが発生する可能性があります。

Error response from daemon: Mounts denied: 
The path /Users/xxx/docker/mysql/initdb.d is not shared from the host and is not known to Docker.
You can configure shared paths from Docker -> Preferences... -> Resources -> File Sharing.
See https://docs.docker.com/desktop/mac for more info.

その場合、Docker Desktop の Settings(歯車アイコン)から Resources > File sharing にエラーの発生したディレクトリを追記、Apply & restart を押します。

スクリーンショット.png

ターミナルも再起動して、再度 docker compose up -d を実行で解消される筈です。

Laravel の導入

プロジェクトの作成・インストール

チーム開発において、最初の人が実施する想定。

コンテナ内の Composer を利用して Laravel をインストールします。

> docker container exec -it app-container composer create-project --prefer-dist laravel/laravel .

Laravel 11 では bootstrap/cache 及び storage ディレクトリに Web サーバーからの書き込み権限が必要な為、付与しておきます。

参考:Deployment - Server Configuration - Directory Permissions

> docker container exec -it app-container chmod -R 777 storage bootstrap/cache

インストール

チーム開発において、後続のメンバーはプロジェクト作成済みのリポジトリをクローン後、composer.lock の情報を基に Laravel をインストールする想定。

> docker container exec -it app-container composer install

.env ファイルの作成とアプリケーションキーの設定を行います。

> docker container exec -it app-container cp .env.example .env
> docker container exec -it app-container php artisan key:generate

共通

Laravel 11 からはデフォルトのデータベース管理システムが SQLite となっています。
本記事では MySQL を採用している為、以下のように .env を変更します。

app/laravel/.env
- DB_CONNECTION=sqlite
- # DB_HOST=127.0.0.1
- # DB_PORT=3306
- # DB_DATABASE=laravel
- # DB_USERNAME=root
- # DB_PASSWORD=
+ DB_CONNECTION=mysql
+ DB_HOST=db
+ DB_PORT=3306
+ DB_DATABASE=database
+ DB_USERNAME=user
+ DB_PASSWORD=password

- SESSION_DRIVER=database
+ SESSION_DRIVER=file

未解決

Laravel プロジェクトを作成した人とリポジトリからクローンした人でコンテナ内のパーミッションが異なる問題。
この件、どのように対応するべきなのかは未解決です。

プロジェクトを作成した人

/var/www# ls -al --time-style="+"
total 316
drwxrwxrwx 1 root root   4096  .
drwxr-xr-x 1 root root   4096  ..
-rw-r--r-- 1 root root    258  .editorconfig
-rw-r--r-- 1 root root   1113  .env
-rw-r--r-- 1 root root   1075  .env.example
-rw-r--r-- 1 root root    186  .gitattributes
-rw-r--r-- 1 root root    258  .gitignore
-rw-r--r-- 1 root root   4109  README.md
drwxr-xr-x 1 root root   4096  app
-rwxr-xr-x 1 root root    350  artisan
drwxr-xr-x 1 root root   4096  bootstrap
-rw-r--r-- 1 root root   1925  composer.json
-rw-r--r-- 1 root root 287463  composer.lock
drwxr-xr-x 1 root root   4096  config
drwxr-xr-x 1 root root   4096  database
-rw-r--r-- 1 root root    244  package.json
-rw-r--r-- 1 root root   1191  phpunit.xml
drwxr-xr-x 1 root root   4096  public
drwxr-xr-x 1 root root   4096  resources
drwxr-xr-x 1 root root   4096  routes
drwxrwxrwx 1 root root   4096  storage
drwxr-xr-x 1 root root   4096  tests
drwxr-xr-x 1 root root   4096  vendor
-rw-r--r-- 1 root root    263  vite.config.js

リポジトリからクローンした人

/var/www# ls -al --time-style="+"
total 316
drwxrwxrwx 1 root root   4096  .
drwxr-xr-x 1 root root   4096  ..
-rwxrwxrwx 1 root root    258  .editorconfig
-rwxr-xr-x 1 root root   1113  .env
-rwxrwxrwx 1 root root   1075  .env.example
-rwxrwxrwx 1 root root    186  .gitattributes
-rwxrwxrwx 1 root root    258  .gitignore
-rwxrwxrwx 1 root root   4109  README.md
drwxrwxrwx 1 root root   4096  app
-rwxrwxrwx 1 root root    350  artisan
drwxrwxrwx 1 root root   4096  bootstrap
-rwxrwxrwx 1 root root   1925  composer.json
-rwxrwxrwx 1 root root 287463  composer.lock
drwxrwxrwx 1 root root   4096  config
drwxrwxrwx 1 root root   4096  database
-rwxrwxrwx 1 root root    244  package.json
-rwxrwxrwx 1 root root   1191  phpunit.xml
drwxrwxrwx 1 root root   4096  public
drwxrwxrwx 1 root root   4096  resources
drwxrwxrwx 1 root root   4096  routes
drwxrwxrwx 1 root root   4096  storage
drwxrwxrwx 1 root root   4096  tests
drwxr-xr-x 1 root root   4096  vendor
-rwxrwxrwx 1 root root    263  vite.config.js

補足

Docker を利用した Laravel のローカル開発環境構築には Laravel Sail という選択肢もあるようです。
本記事では Laravel に限定せず Docker での環境構築を学ぶ主目的があった為、使用していません。

Laravel の確認

http://localhost:8080/

image.png

続いてアプリケーションサーバーからデータベースへ通信できることを確認しておきます。

app/laravel/public/db.php
<?php
const DB_HOST = 'db';
const DB_NAME = 'database';
const DB_USER = 'user';
const DB_PASSWORD = 'password';

try {
    $dbh = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME, DB_USER, DB_PASSWORD);
    echo 'Connection successful.';
} catch (PDOException $e) {
    echo $e->getMessage();
    exit;
}

接続先のホスト名は compose.yaml で定義したサービス名となる点に注意します。

http://localhost:8080/db.php にアクセスして Connection successful. と表示されていれば、疎通成功です。

image.png

phpMyAdmin の確認

http://localhost:4040/

image.png

サービスの停止

compose.yaml に記載されているサービスのコンテナが全て停止されます。

> docker compose stop

コンテナの稼働状況を確認します。
停止しているコンテナを表示する為に -a オプションを使用します。

参考:docker ps

> docker ps -a
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS                      PORTS     NAMES
227d617fbbfd   phpmyadmin   "/docker-entrypoint.…"   9 minutes ago   Exited (0) 35 seconds ago             phpmyadmin-container
d33c7973bec6   app          "docker-php-entrypoi…"   9 minutes ago   Exited (0) 35 seconds ago             app-container
b83d0a07dfb0   db           "docker-entrypoint.s…"   9 minutes ago   Exited (0) 30 seconds ago             db-container

サービスの開始

compose.yaml に記載されているサービスのコンテナが稼働します。
あらかじめ、コンテナが作成されている必要があります。

> docker compose start
> docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS                               NAMES
227d617fbbfd   phpmyadmin   "/docker-entrypoint.…"   13 minutes ago   Up 45 seconds   0.0.0.0:4040->80/tcp                phpmyadmin-container
d33c7973bec6   app          "docker-php-entrypoi…"   13 minutes ago   Up 45 seconds   0.0.0.0:8080->80/tcp                app-container
b83d0a07dfb0   db           "docker-entrypoint.s…"   13 minutes ago   Up 49 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp   db-container

コンテナの削除

compose.yaml に記載されているサービスのコンテナを停止、コンテナとネットワークが削除されます。

> docker compose down
> docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

空白の5年間

いいですか、落ち着いて聞いてください。私が XAMPP を擦り続けている間に

おわり

バイバイ XAMPP ワールド

xampp.jpg

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5