Docker и PHP: продвинутые техники контейнеризации приложений

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Docker и PHP: контейнеризация приложений на продвинутом уровне

Контейнеризация PHP-приложений с помощью Docker давно перестала быть просто удобным инструментом для разработки. На продвинутом уровне это — ключ к созданию масштабируемых, безопасных и воспроизводимых окружений. В этой статье мы разберём техники, которые помогут вам перейти от базового запуска PHP-контейнера к профессиональной оркестрации: мультистейдж-сборка, оптимизация образов, работа с Docker Compose для микросервисной архитектуры и продвинутое кеширование.

1. Мультистейдж-сборка: минимальный финальный образ

Одна из главных проблем стандартных Docker-образов — их размер. Базовый образ php:8.2-apache весит более 400 МБ, а с установкой расширений — все 600+. Для продакшена это недопустимо: большой образ медленнее загружается, занимает место в реестре и увеличивает поверхность атаки.

Мультистейдж-сборка (multi-stage build) позволяет разделить процесс на этапы: один для компиляции и установки зависимостей (с полным набором инструментов), второй — для минимального рантайма. Финальный образ содержит только скомпилированные артефакты и необходимые библиотеки.

Пример Dockerfile для Laravel-приложения:

# Этап 1: Компиляция и установка зависимостей
FROM composer:latest AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-interaction

# Этап 2: Сборка Node-ресурсов (если есть фронтенд)
FROM node:18-alpine AS frontend
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --production
COPY resources/ ./resources/
RUN npm run production

# Этап 3: Финальный PHP-образ
FROM php:8.2-fpm-alpine AS production
RUN docker-php-ext-install pdo_mysql opcache
COPY --from=vendor /app/vendor /var/www/html/vendor
COPY --from=frontend /app/public/build /var/www/html/public/build
COPY . /var/www/html

RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
EXPOSE 9000
CMD ["php-fpm"]

Такой подход сокращает размер образа с 500+ МБ до ~120 МБ. composer:latest и node:18-alpine используются только на этапах сборки и не попадают в финальный слой.

2. Оптимизация кеширования слоёв Docker

Каждая инструкция в Dockerfile создаёт слой. Чтобы ускорить повторные сборки, нужно располагать редко меняющиеся слои как можно раньше. Для PHP-проекта это означает:

  • Копировать composer.json и composer.lock до копирования кода.
  • Запускать composer install до копирования исходников.
  • Копировать код последним.

Пример оптимизированного порядка инструкций:

FROM php:8.2-fpm-alpine AS base
WORKDIR /var/www/html

# Устанавливаем системные зависимости один раз
RUN apk add --no-cache $PHPIZE_DEPS \
    && docker-php-ext-install pdo_mysql opcache bcmath

# Копируем только файлы зависимостей
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-interaction --no-scripts --prefer-dist

# Копируем остальной код
COPY . .

# Генерируем автозагрузку и оптимизируем
RUN composer dump-autoload --optimize

Совет: используйте .dockerignore, чтобы исключить vendor, .git, node_modules и другие временные файлы из контекста сборки. Это ускорит передачу контекста демону Docker.

3. Docker Compose для микросервисной архитектуры

Современные PHP-приложения редко состоят из одного сервиса. Типичная архитектура включает PHP-FPM, Nginx, Redis, очередь задач (RabbitMQ/Beanstalkd) и базу данных. Docker Compose позволяет описать всю инфраструктуру в одном docker-compose.yml.

Пример конфигурации для микросервиса на PHP:

version: '3.8'
services:
  app:
    build:
      context: .
      target: production
    volumes:
      - ./storage:/var/www/html/storage
    env_file:
      - .env
    depends_on:
      - db
      - redis

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

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_DATABASE: ${DB_DATABASE}
    volumes:
      - db_data:/var/lib/mysql
    ports:
      - "3306:3306"

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data

volumes:
  db_data:
  redis_data:

Для масштабирования используйте docker-compose up --scale app=3. Однако для продакшена лучше перейти на оркестратор (Kubernetes или Docker Swarm), где управление репликами и балансировкой автоматизировано.

Продвинутые настройки для PHP-FPM

В конфигурации PHP-FPM внутри контейнера важно настроить пулы для разных приложений. Используйте переменные окружения для динамической настройки:

; /usr/local/etc/php-fpm.d/zz-custom.conf
[www]
pm = dynamic
pm.max_children = ${PHP_FPM_MAX_CHILDREN:-50}
pm.start_servers = ${PHP_FPM_START_SERVERS:-5}
pm.min_spare_servers = ${PHP_FPM_MIN_SPARE_SERVERS:-3}
pm.max_spare_servers = ${PHP_FPM_MAX_SPARE_SERVERS:-10}
pm.max_requests = 500

Передавайте значения через environment в docker-compose.yml:

app:
  environment:
    PHP_FPM_MAX_CHILDREN: 100
    PHP_FPM_START_SERVERS: 10

4. Безопасность и деплой

На продвинутом уровне нельзя забывать о безопасности контейнеров:

  • Не запускайте контейнеры от root. Используйте USER www-data в Dockerfile.
  • Минимизируйте количество установленных пакетов. Используйте php:8.2-fpm-alpine

Блоги

Рекомендаций по книгам