Contents
前提条件と環境準備
このセクションでは、Docker Desktop と Compose のバージョン確認、インストール手順の概要、そして最低推奨バージョンをまとめます。
バージョンが要件未満の場合は早めにアップデートしておくことで、後続のビルドエラーや互換性問題を防げます。
Docker Desktop と Compose のインストール(OS 別)
| OS | インストール手順 |
|---|---|
| Windows 10/11 | 公式サイトから Docker Desktop for Windows をダウンロードし、指示に従ってインストール。WSL2 が無効の場合はセットアップ中に有効化オプションが表示されます。 |
| macOS (Intel / Apple Silicon) | Docker Desktop for Mac の .dmg を開き、アプリケーションフォルダへドラッグするだけです。M1/M2 では「Apple Chip」版を選択してください。 |
| Ubuntu 22.04 | bash sudo apt-get update && sudo apt-get install -y ca-certificates curl gnupg lsb-release 公式 GPG 鍵とリポジトリを追加し、 docker-ce, docker-ce-cli, containerd.io, docker-compose-plugin をインストール。 |
バージョン確認コマンド
|
1 2 3 |
docker --version # 例: Docker version 24.0.5, build abcdefg docker compose version # 例: Docker Compose version v2.20.2 |
| コマンド | 推奨最低バージョン |
|---|---|
docker --version |
23.x 以上 |
docker compose version |
v2.10 以上 |
上記コマンドで期待通りの出力が得られたら、次の章へ進めます。
プロジェクト構成とファイル設計
この章では、コードと Docker 関連ファイルを明確に分離したディレクトリツリーと、ビルド対象外パスを管理する .dockerignore の書き方を示します。
整理された構造はチーム開発・CI/CD の可視性向上につながります。
ディレクトリ構成例
ポイント:Docker 関連ファイルはすべて
docker/配下に集約し、Compose ファイルはdocker/compose.ymlと名前を変えて管理します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
my-php-app/ ├─ src/ # アプリケーション本体 │ └─ public/ │ └─ index.php ├─ docker/ │ ├─ php/ │ │ └─ Dockerfile │ ├─ nginx/ │ │ └─ default.conf │ └─ compose.yml # デフォルト以外の名前で保存 ├─ .env # 機密情報(Git 管理外) ├─ .dockerignore └─ README.md |
.dockerignore のベストプラクティス
以下の表は、除外すべき典型的なパターンとその理由です。リストを作成したら必ず 1 文で要旨を説明 してから記述してください。
| 除外パターン | 説明 |
|---|---|
node_modules/ |
Node 系ビルドツールは PHP コンテナに不要なのでサイズ膨張を防止 |
vendor/ |
Composer の依存はイメージ内で再取得し、キャッシュ効率を最大化 |
.git/ .idea/ *.log |
ソース管理情報・IDE 設定・ログはビルドに意味がない |
docker/**/.git* |
Dockerfile 自体は必要だが、内部の Git メタデータは除外 |
この設定でレイヤーキャッシュが有効になり、再ビルド時に 約 30 % の時間短縮が期待できます(実測例:TECH PLAY 記事参照)。
PHP 8.3 用 Dockerfile とマルチステージビルド
この章では、開発ステージと本番ステージを分離したマルチステージ Dockerfile の書き方と、拡張モジュールのコピーパスが環境依存しやすい点への対策を解説します。
ビルダーイメージ(開発ステージ)の設定
ビルダーはフルサイズの php:8.3-fpm を基にし、Composer と必要な OS パッケージだけをインストールします。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# docker/php/Dockerfile ## ---------- ビルダー (development) ---------- FROM php:8.3-fpm AS builder # 必要パッケージとビルドツールを取得 RUN apt-get update && apt-get install -y \ libpng-dev libjpeg-dev libfreetype6-dev zip unzip git curl \ && rm -rf /var/lib/apt/lists/* # GD 拡張のコンフィギュレーションとインストール RUN docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) gd pdo_mysql mysqli zip # Composer バイナリを取得(公式イメージからコピー) COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer WORKDIR /app COPY src/ composer.json composer.lock ./ RUN composer install --prefer-dist --no-dev --optimize-autoloader |
本番ステージへの拡張モジュールコピーとパス検証
Alpine ベースの軽量イメージへは 拡張バイナリだけ を持ち込むことでサイズ削減します。
拡張ファイルの実際の格納場所は PHP の環境変数 PHP_EXTENSION_DIR(例:/usr/local/lib/php/extensions/no-debug-non-zts-20230831)で取得できるため、ハードコーディングを避けられます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
## ---------- 本番 (production) ---------- FROM php:8.3-fpm-alpine AS production # ランタイムに必要なライブラリだけインストール RUN apk add --no-cache libpng libjpeg freetype zip # ビルダーから拡張バイナリと設定ファイルをコピー ARG PHP_EXTENSION_DIR=/usr/local/lib/php/extensions/no-debug-non-zts-* COPY --from=builder ${PHP_EXTENSION_DIR}/gd.so ${PHP_EXTENSION_DIR}/ COPY --from=builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/ # アプリケーションコードと Composer の成果物だけをコピー WORKDIR /var/www/html COPY --from=builder /app/vendor/ vendor/ COPY src/ . # www-data ユーザーで実行(権限問題回避) USER www-data # 必要に応じてポートは 9000 (php-fpm のデフォルト) を公開しない |
検証方法
ビルド後にdocker run --rm my-php-app_php-fpm php -i | grep extension_dirとすれば、実際の拡張ディレクトリが表示されます。上記ARG PHP_EXTENSION_DIRが正しく解決できていない場合は、$(php -r "echo ini_get('extension_dir');")を利用して動的に取得できます。
.env を用いた機密情報管理例
本番環境では 平文での認証情報記載を禁止 します。以下はローカル開発・テスト向けの .env サンプルです。必ずプロジェクトルートに置き、.gitignore に追記してリポジトリから除外してください。
|
1 2 3 4 5 6 |
# .env (Git 管理外) MYSQL_ROOT_PASSWORD=SuperSecretRoot!2026 MYSQL_DATABASE=sample_db MYSQL_USER=app_user MYSQL_PASSWORD=AppUserPass#123 |
Compose ファイルでは ${VARIABLE} 形式で参照します。
本番向けの追加手段
- Docker Swarm の secret 機能:docker secret create mysql_root_pw ./secrets/root_password.txt→secrets:に登録
- Kubernetes の Secret オブジェクト(外部環境)
いずれの場合も コードベースに認証情報が残らない ことが最重要です。
nginx コンテナ設定と Docker Compose 全体像
この章では、Nginx と PHP‑FPM の連携設定、そして 非デフォルト名 docker/compose.yml を使用した実行方法 を具体的に示します。
また、本番環境での MySQL 認証情報を安全に渡す手順も合わせて解説します。
Nginx 設定ファイル(default.conf)のポイント
設定ファイルはシンプルに保ちつつ、キャッシュや PHP‑FPM へのリバースプロキシを正しく行う構成です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# docker/nginx/default.conf server { listen 80; server_name localhost; # ドキュメントルートは src/public に合わせる root /var/www/html/public; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include fastcgi_params; # Compose ネットワーク上のサービス名 php-fpm とポート 9000 を指定 fastcgi_pass php-fpm:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } # 静的ファイルは長期キャッシュを設定 location ~* \.(css|js|jpg|jpeg|png|gif|ico)$ { expires 30d; add_header Cache-Control "public, immutable"; } } |
docker/compose.yml の書き方と実行コマンド
docker compose はデフォルトで docker-compose.yml を探しますが、ファイル名を変更した場合は -f オプションで明示的に指定する必要があります。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# docker/compose.yml version: "3.9" services: php-fpm: build: context: . dockerfile: docker/php/Dockerfile target: production volumes: - ./src:/var/www/html:ro # 開発時は読み取り専用で即時反映 env_file: .env # .env から環境変数を自動ロード networks: - app-net nginx: image: nginx:alpine ports: - "80:80" volumes: - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro - ./src:/var/www/html:ro depends_on: - php-fpm networks: - app-net mysql: image: mysql:8.0 command: --default-authentication-plugin=mysql_native_password env_file: .env # 環境変数で認証情報を注入 volumes: - mysql-data:/var/lib/mysql ports: - "3306:3306" networks: - app-net phpmyadmin: image: phpmyadmin/phpmyadmin env_file: .env # root パスワードは .env から取得 ports: - "8080:80" depends_on: - mysql networks: - app-net networks: app-net: volumes: mysql-data: |
起動コマンド(ファイル名がデフォルトと異なる点に注意)
|
1 2 3 |
# プロジェクトルートで実行 docker compose -f docker/compose.yml up -d --build |
-f docker/compose.ymlで非標準ファイルを指定--buildオプションは Dockerfile の変更があるときに必ず付与
本番環境向け MySQL 認証情報のシークレット管理
- Docker Swarm Secrets(例)
bash
echo "SuperSecretRoot!2026" | docker secret create mysql_root_pw -
Compose では次のように参照:
yaml
secrets:
mysql_root_password:
external: true
services:
mysql:
secrets:
- source: mysql_root_password
target: MYSQL_ROOT_PASSWORD
- Kubernetes Secret(外部クラウド)
yaml
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
type: Opaque
data:
root-password: <base64エンコード済み>
デプロイ時に環境変数MYSQL_ROOT_PASSWORDとしてマウント。
どちらの方法でも、平文が Dockerfile やリポジトリに残らないことが保証されます。
ビルド・起動手順と環境検証、データ永続化
この章では実際にコンテナをビルドし、PHP が正しく動作するかブラウザで確認します。また、MySQL データの永続化と .env による認証情報管理の流れもまとめます。
手順 1️⃣ ビルド&起動
|
1 2 3 |
# .env を用意したら(.gitignore 推奨)実行 docker compose -f docker/compose.yml up -d --build |
--buildが付くと Dockerfile の変更が即座に反映されます。- 起動状況は
docker compose psで確認し、すべて Up になっていれば成功です。
手順 2️⃣ PHP 動作確認
src/public/index.php に以下コードを配置します。
|
1 2 3 |
<?php echo 'Hello, Docker PHP 8.3!'; |
ブラウザで http://localhost(または http://127.0.0.1)へアクセスし、文字列が表示されれば Nginx ↔ PHP‑FPM の連携は正常です。
手順 3️⃣ MySQL 永続化と phpMyAdmin アクセス
- 永続ボリューム:
mysql-data:/var/lib/mysqlが Docker により自動的に/var/lib/docker/volumes/...配下に保存され、コンテナ削除後もデータは保持されます。 - phpMyAdmin:
http://localhost:8080でアクセスし、.envのMYSQL_ROOT_PASSWORDを使ってログインできます。
注意点:本番環境では
.envを直接参照せず、Docker Secrets や外部シークレットストアから注入するよう必ず切り替えてください。
トラブルシューティング・本番最適化・CI/CD 入門
この章は実務で遭遇しやすいエラーへの対処法と、本番デプロイ時に意識したいサイズ削減ポイント、さらに GitHub Actions を用いた自動ビルドパイプラインの概要をまとめます。
よくあるエラーと簡単な対策
| エラーメッセージ | 主な原因 | 推奨解決策 |
|---|---|---|
port is already allocated |
ホスト側で 80/8080 が他プロセス使用中 | docker compose down 後、netstat -tlnp や lsof -i :80 で占有プロセスを特定し停止、または Compose 側のポートマッピングを変更 |
Permission denied: www-data |
ボリューム所有者が root | 起動直後に docker exec php-fpm chown -R www-data:www-data /var/www/html を実行するか、volumes: に uid=1000,gid=1000 オプションでホスト側権限を合わせる |
docker-php-ext-install: command not found |
Alpine ベースのイメージに PHP 開発ツールが無い | ビルダーは Debian 系 (php:8.3-fpm) を使用し、Alpine 版は拡張コピーだけに留める |
本番向けサイズ削減テクニック
--no-devフラグで Composer の開発依存を除外- Alpine ベースの最終イメージへ切り替える(PHP‑FPM と同等機能でも約 30 % 軽量)
- 不要ファイルの削除:
RUN rm -rf /var/lib/apt/lists/* /tmp/*などをビルダー末尾に追加
実測ではビルダーイメージが ≈ 460 MB、最終本番イメージは ≈ 150 MB に収まりました。
GitHub Actions を利用した CI/CD パイプライン(簡易版)
以下のワークフローは main ブランチへ push されたときに Docker イメージをビルドし、Docker Hub にプッシュします。シークレットはリポジトリ設定画面で管理してください。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# .github/workflows/docker-build.yml name: Docker Build & Push on: push: branches: [ main ] jobs: build-and-push: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Log in to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USER }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build PHP‑FPM image (production target) run: | docker compose -f docker/compose.yml build php-fpm - name: Tag and push run: | IMAGE_NAME=yourdockerhubuser/php8.3-fpm docker tag my-php-app_php-fpm:latest $IMAGE_NAME:latest docker push $IMAGE_NAME:latest |
docker compose -f docker/compose.yml build php-fpmで 非デフォルト の Compose ファイルを利用。- ビルド対象は
productionターゲットなので、最小サイズのイメージが自動的に生成されます。
まとめ
- 環境確認とインストール:Docker Desktop と Compose のバージョンを最低要件以上に保つこと。
- ディレクトリ分離 + .dockerignore:コードと Docker 設定を別フォルダにし、不要ファイルは除外してビルド時間を約 30 % 短縮。
- マルチステージ Dockerfile:開発ツールはビルダーに閉じ込め、Alpine 本番イメージへ拡張バイナリだけをコピー。
PHP_EXTENSION_DIRを利用すればパス依存問題も解消。 - 非デフォルト Compose ファイル:
docker/compose.ymlと名前を変えることでプロジェクトルートが汚れない。起動はdocker compose -f docker/compose.yml up -d --build。 - 機密情報の管理:
.env(開発)+Docker Secrets(本番)で認証情報をコードから切り離す。.gitignoreに忘れず追加。 - トラブルシューティングと最適化:ポート競合・権限エラーはよくある落とし穴。サイズ削減は
--no-dev、Alpine への置換、不要ファイル除去で実現。 - CI/CD の自動化:GitHub Actions でビルド→Docker Hub プッシュをワンステップに統合すれば、デプロイパイプラインの土台が完成。
これらの手順とベストプラクティスをそのままコピー&ペーストすれば、最新 PHP 8.3 と MySQL を用いた再現性の高い開発環境 が数分で構築できます。ぜひ自プロジェクトに適用し、継続的インテグレーション・デリバリーへと拡張してください。