また今度が来るまでに 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
ファイル詳細
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.yaml
内 db
サービスの volumes
ではマウントを使用したホスト側へのデータ保存、初期データの投入を設定しています。
初期データの投入はお試しで書いたので、不要であれば割愛して問題ありません。
*
!.gitignore
当該フォルダをあらかじめ Git 管理に含めておきたいので .gitignore
を置きます。
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);
初期データ投入のお試し用です。
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
の中で良い感じにしてやります。
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
[mysql]
default-character-set = utf8mb4
[client]
default-character-set = utf8mb4
照合順序は信頼と実績の utf8mb4_general_ci
を採用していますが、お好みでどうぞ。
app サービス
Laravel の場合、ドキュメントルートの変更(下記 Dockerfile
参照)が必要です。その上で public
と同階層のディレクトリおよびファイルもコンテナへ同期する(compose.yaml
内 app
サービスの volumes
参照)必要があります。
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 で必須要件となっている拡張をインストールしています。
※コメントアウトは採用したコンテナイメージで標準インストールされており不要だったものです。
[Date]
date.timezone = Asia/Tokyo
[mbstring]
mbstring.language = Japanese
ここもお好みで。
phpmyadmin サービス
compose.yaml
の environment
> PMA_HOST
には接続するデータベースのサービス名、PMA_PASSWORD
には接続するデータベースサービスの environment
> MYSQL_ROOT_PASSWORD
で定義された値を指定する。
*
!.gitignore
当該フォルダをあらかじめ Git 管理に含めておきたいので .gitignore
を置きます。
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
を押します。
ターミナルも再起動して、再度 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
を変更します。
- 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 の確認
続いてアプリケーションサーバーからデータベースへ通信できることを確認しておきます。
<?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. と表示されていれば、疎通成功です。
phpMyAdmin の確認
サービスの停止
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 を擦り続けている間に
- Docker Compose の
docker-compose
コマンドではなく Docker のサブコマンドであるdocker compose
コマンド推奨に変わっていた - 設定ファイルは
docker-compose.yml
ではなくcompose.yaml
推奨に変わっていた - 設定ファイル内のバージョン指定
version
が廃止されていた(下位互換性があり、指定していても問題はないが非推奨)
おわり
バイバイ XAMPP ワールド