PHP-FPMをDockerで構築する方法について

採用はこちら

PHP-FPMをDockerで構築する場合は、PHP-FPMとWebサーバーを別々のコンテナに分ける構成が基本です。

代表的なのは、NginxとPHP-FPMを組み合わせる構成です。

ブラウザ
   ↓
Nginxコンテナ
   ↓ FastCGI
PHP-FPMコンテナ
   ↓
PHPアプリケーション

NginxがHTTPリクエストを受け取り、PHPファイルの処理が必要な場合はFastCGI経由でPHP-FPMへ処理を渡します。

PHP-FPMは受け取ったPHPファイルを実行し、その結果をNginxへ返します。

Dockerを利用すれば、NginxやPHP-FPMをそれぞれ独立したコンテナとして管理できるため、開発環境を統一しやすくなります。

目次

PHP-FPMとは

PHP-FPMは「PHP FastCGI Process Manager」の略称です。

PHPをFastCGI方式で動作させるための仕組みで、PHPを実行する複数のプロセスを効率的に管理します。

PHP-FPMはWebサーバーではない

PHP-FPM自体は、NginxやApacheのような一般的なWebサーバーではありません。

通常はNginxなどのWebサーバーと組み合わせて使用します。

処理の流れは次のようになります。

ユーザー
   ↓
Nginx
   ↓
PHP-FPM
   ↓
PHPアプリケーション
   ↓
PHP-FPM
   ↓
Nginx
   ↓
ユーザー

HTMLやCSS、JavaScript、画像などの静的ファイルはNginxが配信し、PHPの実行が必要な場合だけPHP-FPMへ処理を渡す構成が一般的です。

DockerでPHP-FPM環境を構築する

ここでは、NginxとPHP-FPMをDocker Composeで構築する方法を紹介します。

ディレクトリ構成は次のようにします。

php-fpm-docker/
├── compose.yaml
├── docker/
│   ├── php/
│   │   └── Dockerfile
│   └── nginx/
│       └── default.conf
└── src/
    └── index.php

Docker Composeを利用すると、PHP-FPMやNginxなど複数のコンテナを1つの設定ファイルでまとめて管理できます。

PHP-FPM用のDockerfileを作成する

まず、docker/php/Dockerfileを作成します。

FROM php:8.4-fpm

WORKDIR /var/www/html

COPY ./src /var/www/html

PHP公式のFPMイメージを使用する

PHPの公式DockerイメージにはFPM版が用意されているため、PHP-FPMを一からインストールする必要はありません。

例えば、

FROM php:8.4-fpm

と指定すれば、PHP 8.4とPHP-FPMを含んだイメージを利用できます。

PHPのバージョンについては、実際のプロジェクト要件やサポート期間に合わせて選択することが重要です。

COPYのパスに注意する

今回のDocker Composeでは、プロジェクトルートをビルドコンテキストにします。

そのため、Dockerfileでは、

COPY ./src /var/www/html

と指定します。

COPYのコピー元はDockerfileが置かれている場所ではなく、Dockerのビルドコンテキストを基準に指定します。

Nginxの設定ファイルを作成する

次に、docker/nginx/default.confを作成します。

server {
    listen 80;

    server_name localhost;

    root /var/www/html;

    index index.php index.html;

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

    location ~ \.php$ {
        include fastcgi_params;

        fastcgi_pass php:9000;

        fastcgi_index index.php;

        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

fastcgi_passでPHP-FPMへ処理を渡す

特に重要なのが次の部分です。

fastcgi_pass php:9000;

ここでNginxからPHP-FPMコンテナへPHPの処理を渡しています。

phpはDocker Composeで定義するサービス名です。

services:
  php:

同じDocker Composeネットワーク内では、コンテナ同士をサービス名で参照できます。

そのため、NginxコンテナからPHP-FPMへ接続するときは、

fastcgi_pass localhost:9000;

ではなく、

fastcgi_pass php:9000;

と指定します。

Nginxコンテナ内でlocalhostを指定すると、Nginxコンテナ自身を指してしまうためです。

try_filesはフロントコントローラー型の構成で使われる

次の設定は、Laravelなどのフレームワークでもよく利用されます。

try_files $uri $uri/ /index.php?$query_string;

存在するファイルやディレクトリが見つからなかった場合に、リクエストをindex.phpへ渡す設定です。

単純に複数のPHPファイルを直接配置するだけの構成では、必ずしも必要ではありません。

compose.yamlを作成する

続いて、プロジェクトルートにcompose.yamlを作成します。

services:
  php:
    build:
      context: .
      dockerfile: ./docker/php/Dockerfile

    volumes:
      - ./src:/var/www/html

  nginx:
    image: nginx:alpine

    ports:
      - "8080:80"

    volumes:
      - ./src:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro

    depends_on:
      - php

この設定では、

php
nginx

という2つのサービスを起動します。

PHP-FPMコンテナの設定

PHP-FPM側は次の設定です。

php:
  build:
    context: .
    dockerfile: ./docker/php/Dockerfile

  volumes:
    - ./src:/var/www/html

buildでDockerfileからイメージを作成する

build:
  context: .
  dockerfile: ./docker/php/Dockerfile

では、プロジェクトルートをビルドコンテキストとして、指定したDockerfileからPHP-FPM用のイメージを作成します。

volumesでPHPファイルを共有する

volumes:
  - ./src:/var/www/html

では、ホスト側のsrcディレクトリと、PHP-FPMコンテナ側の/var/www/htmlを共有します。

開発環境では、ローカル側でPHPファイルを編集するとコンテナ側にも反映されるため便利です。

Nginxコンテナの設定

Nginx側は次の設定です。

nginx:
  image: nginx:alpine

  ports:
    - "8080:80"

  volumes:
    - ./src:/var/www/html
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro

  depends_on:
    - php

ポート8080からアクセスする

次の設定では、

ports:
  - "8080:80"

ホスト側の8080番ポートと、Nginxコンテナ側の80番ポートを接続しています。

そのため、ブラウザから、

http://localhost:8080

へアクセスできます。

Nginx側にもsrcをマウントする

Nginx側にも、

- ./src:/var/www/html

を設定しています。

Nginxは静的ファイルを配信したり、try_filesでファイルの存在を確認したりするため、Nginx側からもアプリケーションファイルを参照できる必要があります。

index.phpを作成する

src/index.phpを作成します。

<?php

phpinfo();

これでPHPの動作確認ができます。

phpinfo()はPHPの設定情報やサーバー情報を詳しく表示するため、本番環境で公開し続けるのは避けましょう。

動作確認後は削除することをおすすめします。

Dockerコンテナを起動する

プロジェクトルートで次のコマンドを実行します。

docker compose up -d --build

--buildを付けることで、必要に応じてDockerイメージをビルドしてからコンテナを起動できます。

起動後、ブラウザから次のURLへアクセスします。

http://localhost:8080

PHPの情報画面が表示されれば、

Nginx
   ↓
PHP-FPM
   ↓
PHP

という連携が正常に動作しています。

Dockerコンテナの状態を確認する

起動中のコンテナを確認するには、次のコマンドを使用します。

docker compose ps

正常に起動していれば、PHPとNginxのサービスがUpなどの状態で表示されます。

ログを確認する

すべてのサービスのログを確認する場合は、

docker compose logs

リアルタイムで確認する場合は、

docker compose logs -f

を使用します。

PHP-FPMだけを確認したい場合は、

docker compose logs -f php

Nginxだけを確認する場合は、

docker compose logs -f nginx

と指定できます。

PHP-FPMコンテナ内でコマンドを実行する

PHP-FPMコンテナ内でコマンドを実行したい場合は、

docker compose exec php bash

を使用します。

PHPのバージョンを確認する場合は、

php -v

インストール済みのPHP拡張機能を確認する場合は、

php -m

PHP-FPMの設定を確認する場合は、

php-fpm -tt

などを利用できます。

MySQLを追加する場合

PHPアプリケーションでは、MySQLなどのデータベースを利用するケースも多くあります。

MySQLを追加すると、次のような構成になります。

ブラウザ
   ↓
Nginx
   ↓
PHP-FPM
   ↓
MySQL

Composeファイルは、例えば次のようにできます。

services:
  php:
    build:
      context: .
      dockerfile: ./docker/php/Dockerfile

    volumes:
      - ./src:/var/www/html

    depends_on:
      - db

  nginx:
    image: nginx:alpine

    ports:
      - "8080:80"

    volumes:
      - ./src:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro

    depends_on:
      - php

  db:
    image: mysql:8.4

    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: sample
      MYSQL_USER: sample
      MYSQL_PASSWORD: password

    volumes:
      - mysql_data:/var/lib/mysql

volumes:
  mysql_data:

MySQLデータはボリュームへ保存する

次の設定では、

volumes:
  - mysql_data:/var/lib/mysql

MySQLのデータをDockerの名前付きボリュームへ保存しています。

コンテナを作り直した場合でも、ボリュームを削除しない限りデータを保持しやすくなります。

ただし、

docker compose down -v

のようにボリュームも削除すると、保存されているデータも失われる可能性があるため注意が必要です。

PHPからMySQLへ接続する

PHPからMySQLへPDOで接続する場合は、pdo_mysql拡張機能が必要です。

Dockerfileを次のように変更します。

FROM php:8.4-fpm

RUN docker-php-ext-install pdo_mysql

WORKDIR /var/www/html

COPY ./src /var/www/html

変更後は再ビルドします。

docker compose up -d --build

MySQLのホスト名はdbを指定する

Docker Compose環境では、PHPコンテナからMySQLへ接続するときにlocalhostを指定しません。

今回のサービス名は、

db:

なので、ホスト名にはdbを指定します。

例えばPDOでは次のようになります。

<?php

$pdo = new PDO(
    'mysql:host=db;dbname=sample;charset=utf8mb4',
    'sample',
    'password'
);

PHPコンテナ内でlocalhostを指定すると、PHPコンテナ自身を指すため、MySQLコンテナへ接続できません。

depends_onの注意点

Docker Composeでは、

depends_on:
  - db

と指定すると、依存するサービスの起動順序を制御できます。

ただし、depends_onを指定しただけでは、MySQLが実際に接続可能な状態になるまで待ってくれるわけではありません。

そのため、アプリケーション起動直後にMySQLへ接続すると、タイミングによっては接続エラーになる場合があります。

healthcheckを利用する方法もある

より確実にサービスの準備状態を確認する場合は、healthcheckを設定し、service_healthyを利用する方法があります。

例えば次のように構成します。

db:
  image: mysql:8.4

  environment:
    MYSQL_ROOT_PASSWORD: root
    MYSQL_DATABASE: sample
    MYSQL_USER: sample
    MYSQL_PASSWORD: password

  healthcheck:
    test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
    interval: 10s
    timeout: 5s
    retries: 5

PHP側では、

depends_on:
  db:
    condition: service_healthy

のように設定できます。

パスワードをComposeファイルへ直接書く場合の注意点

開発環境のサンプルでは、

MYSQL_ROOT_PASSWORD: root
MYSQL_PASSWORD: password

のように簡単なパスワードを直接記述することがあります。

ただし、このような書き方はローカル開発用の簡易例として考えたほうがよいでしょう。

本番環境では、データベースのパスワードやAPIキーなどの機密情報をソースコードやComposeファイルへ直接記述しないことが重要です。

環境変数やSecretsなど、用途に適した機密情報管理の仕組みを利用します。

PHP-FPMの設定を変更する

PHP-FPMでは、php-fpm.confやPool設定ファイルを使ってプロセス数などを調整できます。

例えば次のような設定があります。

pm = dynamic

pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 5

pm.max_childrenは同時処理数に関係する

pm.max_childrenは、PHP-FPMが同時に処理できる子プロセス数に関係する重要な設定です。

値を大きくすれば単純に性能が上がるわけではありません。

PHPプロセスが使用するメモリ量やサーバー全体のメモリ容量、アクセス数などを考慮して調整する必要があります。

小規模なローカル開発環境であれば、まずはデフォルト設定から始めてもよいでしょう。

開発環境と本番環境で構成を分ける

開発環境では、Bind Mountを使う構成が便利です。

ローカルファイル
   ↓
Bind Mount
   ↓
コンテナ

ファイルを編集するとすぐコンテナへ反映されるため、開発効率が高くなります。

一方、本番環境ではアプリケーションコードをDockerイメージへ組み込む構成も一般的です。

ソースコード
   ↓
Dockerイメージ
   ↓
コンテナ

例えば次のようにします。

FROM php:8.4-fpm

RUN docker-php-ext-install pdo_mysql

WORKDIR /var/www/html

COPY ./src /var/www/html

本番環境では、開発用のBind Mountをそのまま使用するのではなく、デプロイ方法や運用方針に合わせて構成を分けることが重要です。

.dockerignoreも設定する

Dockerイメージをビルドするときは、.dockerignoreを設定して不要なファイルをビルドコンテキストから除外すると効率的です。

例えば次のように設定できます。

.git
.env
node_modules

プロジェクト構成によってはvendorなども対象になりますが、Composerの依存関係をどの段階でインストールするかによって設定は変わります。

不要なファイルをビルドコンテキストへ含めないことで、ビルド時間やイメージ管理を改善しやすくなります。

PHP-FPMをDockerで構築するメリット

DockerでPHP-FPM環境を構築する大きなメリットは、開発環境を設定ファイルとして管理できることです。

例えば、

FROM php:8.4-fpm

と記述しておけば、使用するPHPのバージョンを明確にできます。

開発者ごとにPHPのバージョンや設定が異なる問題も減らしやすくなります。

NginxやMySQLを分離して管理できる

Dockerでは、

Nginx
PHP-FPM
MySQL
Redis

などを別々のコンテナとして管理できます。

役割ごとにコンテナを分離できるため、構成を理解しやすく、必要なサービスだけを変更しやすい点もメリットです。

Docker Composeを利用すれば、それらのサービスを1つのcompose.yamlでまとめて管理できます。

PHP-FPMをDockerで構築するときのポイント

PHP-FPMをDockerで構築する場合は、まずNginxとPHP-FPMの2コンテナ構成から始めると理解しやすいでしょう。

基本的な構成は次の通りです。

ブラウザ
   ↓
Nginxコンテナ
   ↓
PHP-FPMコンテナ
   ↓
必要に応じてMySQLコンテナ

PHP-FPMはPHPを実行するFastCGIプロセスマネージャーであり、一般的にはNginxなどのWebサーバーと組み合わせて利用します。

DockerではPHP公式のFPMイメージを利用できるため、

FROM php:8.4-fpm

のように指定するだけで、PHP-FPM環境の土台を簡単に用意できます。

さらにDocker Composeを使えば、Nginx、PHP-FPM、MySQLなどをまとめて管理できます。

開発環境ではBind Mountを利用し、本番環境ではアプリケーションをDockerイメージへ組み込むなど、目的に応じて構成を使い分けることも重要です。

まずはNginxとPHP-FPMの最小構成を構築し、必要に応じてMySQLやRedisなどのサービスを追加していくと、DockerによるPHP開発環境を理解しやすくなります。

以上、PHP-FPMをDockerで構築する方法についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次