Контейнеризация PHP при помощи Docker: от разработки до продакшена

Раздел: DevOps

Зачем Docker для PHP проектов

Docker позволяет изолировать окружение PHP приложения, гарантируя идентичность настроек на всех этапах - от локальной разработки до production. Это решает проблему «на моей машине работает» и упрощает развертывание.

Основное решение: PHP-FPM + Nginx + Docker Compose

Как создать минимальное окружение PHP с Nginx и PHP-FPM в Docker?

Используется два сервиса: web (Nginx) и app (PHP-FPM). Они общаются через общий volume и внутреннюю сеть.

# docker-compose.yml
version: '3.8'

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./public:/var/www/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
    networks:
      - appnet

  app:
    image: php:8.2-fpm-alpine
    volumes:
      - ./public:/var/www/html
    environment:
      PHP_IDE_CONFIG: "serverName=Docker"
    networks:
      - appnet

networks:
  appnet:

обработка php (обработка данных в php)

# nginx.conf
server {
    listen 80;
    root /var/www/html;
    index index.php index.html;

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

    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Php learning (обучение php)

Пояснения: контейнер app использует официальный образ PHP с FPM. Директория ./public монтируется в оба контейнера. Nginx обрабатывает статику, а PHP-файлы переадресует на fastcgi через порт 9000.

Типичная ошибка: файл nginx.conf не читается из-за неправильного пути монтирования. Убедитесь, что целевая папка в контейнере - /etc/nginx/conf.d/.

Ошибка File not found - часто из-за того, что PHP-FPM не видит файлы. Проверьте SCRIPT_FILENAME и пути volume.

Варианты настройки

Как заменить Nginx на Apache?

Используем образ php:8.2-apache. Встроенный mod_php не требует отдельного FPM, но для производительности лучше использовать FPM.

services:
  web-apache:
    image: php:8.2-apache
    ports:
      - "8080:80"
    volumes:
      - ./public:/var/www/html
    # можно также включить mod_rewrite:
    # docker-php-ext-enable rewrite

Php учебник (учебник по php)

Этот вариант проще, но хуже масштабируется. Подходит для простых проектов.

Как собрать образ с дополнительными расширениями PHP?

Напишите собственный Dockerfile, который наследует официальный образ и устанавливает нужные расширения.

FROM php:8.2-fpm-alpine

RUN docker-php-ext-install pdo_mysql mysqli bcmath

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

COPY . /var/www/html
WORKDIR /var/www/html

CMD ["php-fpm"]

Apis php (api на php)

Расширения (pdo_mysql, bcmath) устанавливаются через встроенные скрипты. Композер копируется из официального образа - это экономит размер.

Проблема: при копировании COPY --from=composer может возникнуть конфликт версий. Используйте точную версию, например composer:2.7.

Как оптимизировать образ для продакшена с помощью multi-stage сборки?

Первый этап - сборка зависимостей (composer install), второй - чистый образ с минимальным набором.

# Dockerfile.prod
FROM composer:2 AS build
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader

FROM php:8.2-fpm-alpine
COPY --from=build /app/vendor ./vendor
COPY . /var/www/html
# ...

Php categoryid (категории в php)

Итоговый образ не содержит composer, dev-зависимостей и лишних файлов.

Как использовать Alpine образы для уменьшения размера?

В примерах выше уже используется php:8.2-fpm-alpine. Альтернатива - php:8.2-cli-alpine для консольных задач. Размер ~100 МБ против 300+ МБ у стандартного Debian.

Внимание: Alpine использует musl, что может вызвать несовместимость с некоторыми C-расширениями (например, imagick). Для таких случаев используйте образ на основе Debian.

Как настроить Xdebug в Docker для отладки?

Добавьте в Dockerfile установку xdebug и настройте host.docker.internal в качестве remote_host.

FROM php:8.2-fpm-alpine
RUN pecl install xdebug \
    && docker-php-ext-enable xdebug \
    && echo "xdebug.mode=debug" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
    && echo "xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini

Html javascript php (интеграция html, javascript и php)

Для PhpStorm дополнительно настройте Path mappings в Docker сервере.

Как выполнять composer команды без установки в образ?

Используйте временный контейнер composer с монтированием исходного кода.

docker run --rm -v $(pwd):/app composer install --no-dev

Это не загромождает основной образ и подходит для CI/CD.

Общие рекомендации и ошибки

При работе с Docker для PHP часто встречаются:

  • Права доступа: www-data (uid 33) в контейнере не совпадает с uid хоста. Решается установкой user в docker-compose или настройкой маппинга через переменные.
  • Использование docker-php-ext-install или pecl зависит от расширения. Для некоторых требуется предварительная установка системных пакетов (например, libzip-dev).
  • Кэширование слоёв Dockerfile: располагайте редко изменяемые инструкции (установка расширений) вверху, а копирование кода - внизу.
- Php javascript css (javascript и css в php)
- Php m3u (создание m3u плейлиста на php)
- Php pid (идентификатор процесса (pid) в php)

Расширенные примеры конфигураций

Ниже приведены нестандартные сценарии и детальные конфигурации с пояснениями.

Пример 1: Docker Compose с Redis и healthcheck

Пример
version: '3.8'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    environment:
      - REDIS_HOST=redis
    depends_on:
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "php", "-r", "echo 'OK';"]
      interval: 30s

  redis:
    image: redis:alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s

Объяснение: healthcheck позволяет убедиться, что Redis готов к работе, прежде чем PHP попытается подключиться. Команда php -r 'echo "OK";' проверяет, что PHP-FPM корректно обрабатывает запросы.

# При запуске docker-compose up вы увидите:
redis    | 1:M 01 Jan 2025 12:00:00.000 * Ready to accept connections
app      | healthcheck: HTTP/1.1 200 OK

Пример 2: Запуск artisan команд (Laravel) в отдельном сервисе

Пример
services:
  scheduler:
    build: .
    command: ['php', 'artisan', 'schedule:work']
    volumes:
      - .:/var/www/html
    restart: unless-stopped
    # Для миграций используйте docker-compose run:
    # docker-compose run --rm artisan migrate

Такой сервис запускает планировщик Laravel в фоне, не блокируя веб-контейнер.

Пример 3: Сборка с несколькими расширениями и системными зависимостями

Пример
FROM php:8.2-fpm-bookworm

# Установка системных пакетов для расширений
RUN apt-get update && apt-get install -y \
    libzip-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    zip \
    unzip

# Настройка и установка расширений
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd pdo_mysql zip bcmath opcache

# Копирование конфигурации PHP (opcache.ini и т.д.)
COPY php.ini /usr/local/etc/php/conf.d/custom.ini

В этом примере показано, как устанавливать зависимости для GD, Zip, PDO. Использование -j$(nproc) ускоряет компиляцию на многоядерных хостах.

Пример 4: Production образ с минимальным набором инструментов

Пример
# Dockerfile.prod (multi-stage)
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-interaction

FROM node:18 AS assets
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --production
COPY resources/js ./resources/js
RUN npm run build

FROM php:8.2-fpm-alpine
RUN docker-php-ext-install pdo_mysql opcache && \
    docker-php-ext-enable opcache

COPY --from=vendor /app/vendor ./vendor
COPY --from=assets /app/public/build ./public/build
COPY . /var/www/html

RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache

USER www-data
EXPOSE 9000
CMD ["php-fpm"]

Итоговый образ содержит только минимально необходимые файлы для работы приложения. Размер такого образа обычно не превышает 200 МБ.

Docker для PHP-приложений - comments

En
Docker php (php)