0Pricing
PHP Academy · レッスン

ローカル環境向けDocker Compose

PHP、データベース、キャッシュをローカルでまとめて実行します。

「ローカル環境向けDocker Compose」はCoddyKit上の無料PHP Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPHP Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 PHP Academyコースには全4レッスンが含まれています。

Composeによるローカルスタック

実際のPHPアプリはPHPだけでは動きません。データベース、キャッシュ、ときにはキューやメールキャッチャーも必要です。Docker Composeを使うと、これらを1つのファイルでサービスとして宣言し、共有ネットワークに接続して、名前で互いにアクセスできるようにします。

このレッスンでは、ボリューム、ヘルスチェック、依存関係の順序付けを含む、PHP-FPM + nginx + MySQL + Redisの完全なローカルスタックを構築します。

サービスの基本構成

Composeファイルでは、services:の下にサービスを列挙します。各サービスはDockerfileからbuildすることも、imageを取得することもできます。Composeは、すべてのサービスがキーで到達できるデフォルトネットワークを作成します。PHPアプリはMySQLにlocalhostではなくホストdbで接続します。

services:
  app:
    build:
      context: .
      target: dev          # multi-stage dev target
    volumes:
      - ./:/app            # live code mount
    depends_on:
      db:
        condition: service_healthy
  db:
    image: mysql:8.4
  redis:
    image: redis:7-alpine

FPMの前段にnginxを置く

FPMはHTTPではなく、ポート9000でFastCGIを使用します。nginxがHTTPを終端し、.phpリクエストをapp:9000にプロキシします。nginxの設定では、Compose上の名前でPHPサービスを参照します。

# docker/nginx/default.conf
server {
  listen 80;
  root /app/public;
  index index.php;

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

  location ~ \.php$ {
    fastcgi_pass app:9000;       # service name from compose
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
  }
}

Webサービスを接続する

nginxサービスは、SCRIPT_FILENAMEを解決するために同じコードと設定ファイルをマウントし、ポート80を公開し、appに依存します。両方が/appを共有するため、FastCGIの両側でパスが一致します。

services:
  web:
    image: nginx:1.27-alpine
    ports:
      - "8080:80"
    volumes:
      - ./:/app:ro
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - app

永続ボリューム

コンテナのファイルシステムは一時的なものです。名前付きボリュームを使うと、docker compose downの後もデータベースファイルを保持できます。バインドマウント(./:/app)を使うと、開発中にホスト上のコードをリアルタイムで同期できます。状態を持つデータには名前付きボリュームを、ソースにはバインドマウントを使ってください。

services:
  db:
    image: mysql:8.4
    environment:
      MYSQL_DATABASE: app
      MYSQL_USER: app
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: rootsecret
    volumes:
      - dbdata:/var/lib/mysql

volumes:
  dbdata:        # survives `down`, removed only by `down -v`

ヘルスチェックとdepends_on

depends_onだけでは、コンテナが起動するまでしか待機せず、MySQLが接続を受け付ける状態になるまで待機しません。healthcheckを追加し、condition: service_healthyを使うことで、DBの準備が実際に完了するまでアプリを待機させてください。

services:
  db:
    image: mysql:8.4
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-prootsecret"]
      interval: 5s
      timeout: 3s
      retries: 10
  app:
    build: .
    depends_on:
      db:
        condition: service_healthy   # waits for healthcheck pass

環境変数と.env

Composeは変数の置換用に、同じディレクトリにある.envを自動的に読み込みます。アプリの設定はenvironmentまたはenv_fileで渡します。コミットするComposeファイルにシークレットを含めず、代わりに変数を参照してください。

services:
  app:
    build: .
    env_file:
      - .env
    environment:
      DATABASE_URL: "mysql://app:secret@db:3306/app"
      REDIS_URL: "redis://redis:6379"
# .env (gitignored) provides ${...} substitutions
#   MYSQL_PASSWORD=secret

PHPから接続する

ネットワーク内では、ホスト名がサービス名になります。PHPコードからはdbとredisに直接接続します。このスニペットは、設定レイヤーが行うようにDSNを解析し、Composeのサービス名が接続文字列にどのように組み込まれるかを示します。

<?php
$dsn = 'mysql://app:secret@db:3306/app';
$p = parse_url($dsn);

printf("driver: %s\n", $p['scheme']);
printf("host:   %s\n", $p['host']);   // 'db' resolves via compose DNS
printf("port:   %d\n", $p['port']);
printf("db:     %s\n", ltrim($p['path'], '/'));

$pdoDsn = sprintf('mysql:host=%s;port=%d;dbname=%s', $p['host'], $p['port'], ltrim($p['path'], '/'));
echo $pdoDsn . PHP_EOL;
?>

ローカル開発用のXdebug

Xdebugの設定は、devビルドターゲットを通じてローカル環境でのみマウントしてください。client_hostをhost.docker.internalに設定すると、デバッガーがホスト上のIDEに接続できます。Xdebugはパフォーマンスを大幅に低下させるため、本番環境には決して含めないでください。

; docker/php/xdebug.ini  (mounted only in dev)
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003

単発コマンドを実行する

docker compose runは、マイグレーション、テスト、Composerの実行用に一時的なコンテナを起動します。execは、すでに実行中のサービス内でコマンドを実行します。使い捨てのコンテナをクリーンアップできるよう、タスクにはrun --rmを使ってください。

# Run migrations against the running db
docker compose exec app php bin/console doctrine:migrations:migrate

# One-off: install deps without a long-lived container
docker compose run --rm app composer install

# Tail logs of just the web service
docker compose logs -f web

オーバーライドファイル

Composeはdocker-compose.ymlとdocker-compose.override.ymlを自動的にマージします。ベースファイルには本番を想定したデフォルト設定を保ち、開発専用のボリューム、ポート、Xdebugはオーバーライドに記述してください。これにより、CIはベースファイルを使い、開発者は追加設定をそのまま利用できます。

# docker-compose.override.yml (auto-merged, dev only)
services:
  app:
    volumes:
      - ./docker/php/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini:ro
    environment:
      APP_ENV: dev
# CI runs: docker compose -f docker-compose.yml up  (no override)

確認

マイグレーションを実行する前に、単純なdepends_on: [db]だけでは不十分なのはなぜですか?

まとめ

Composeでローカルスタックを構築しました。nginxの背後にPHP-FPMを配置し(FastCGIでapp:9000に接続)、サービス名でMySQLとRedisにアクセスし、永続化には名前付きボリュームを使い、ヘルスチェックでdepends_onを制御し、環境変数による設定を行い、開発専用のオーバーライドでXdebugを有効にし、run/execで単発コマンドを実行しました。

覚えておくこと: サービス名はDNSホスト名として機能し、オーバーライドファイルによって開発用の追加設定をCIから分離でき、ヘルスチェックは単純な起動順序より信頼できます。

よくある質問

「ローカル環境向けDocker Compose」レッスンは無料ですか?

はい。「ローカル環境向けDocker Compose」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、PHP Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 PHP Academyコースには全4レッスンが含まれています。

「ローカル環境向けDocker Compose」で何を学びますか?

PHP、データベース、キャッシュをローカルでまとめて実行します。 ブラウザで直接実行するハンズオンコードでPHP Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

PHP Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPHP Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「ローカル環境向けDocker Compose」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPHP Academyレッスンでコードを書いて実行できますか?

はい。すべてのPHP Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. PHPアプリケーションのコンテナ化
  2. マルチステージビルドと最適化
  3. ローカル環境向けDocker Compose
  4. GitHub ActionsによるCI/CD
← PHP Academyに戻る