Почему каждый PHP-разработчик должен освоить Docker?
Вы когда-нибудь сталкивались с ситуацией, когда локально всё работает идеально, а на сервере — «белый экран смерти»? Или, что ещё хуже, когда коллега говорит: «У меня всё работает, обнови composer» — и ваш проект превращается в тыкву? Знакомо? Тогда добро пожаловать в мир контейнеризации PHP приложений с Docker.
Docker — это не просто модный buzzword. Это инструмент, который навсегда изменит ваш подход к разработке. Представьте: вы больше не тратите часы на настройку окружения. Не нужно ставить XAMPP, OpenServer или мучиться с версиями PHP. Один docker-compose up — и ваше приложение живёт в изолированном, предсказуемом мире. И этот мир можно передать коллеге, залить на сервер или даже продать заказчику. В этой статье мы разберём контейнеризацию PHP приложений от А до Я: от базового Dockerfile до продакшен-оптимизации.
Что такое контейнеризация и зачем она PHP?
Контейнеризация — это способ упаковки приложения вместе со всеми его зависимостями (PHP, расширениями, веб-сервером, базой данных) в изолированную среду — контейнер. В отличие от виртуальных машин, контейнеры легковесны, запускаются за секунды и потребляют минимум ресурсов.
Для PHP это особенно актуально. Почему? Потому что типичное PHP-приложение — это связка: PHP-FPM, Nginx или Apache, MySQL/PostgreSQL, Redis, очередь задач. Ручная настройка этой экосистемы на каждой машине — ад. А с Docker вы описываете всю инфраструктуру в коде (Infrastructure as Code) и воспроизводите её одной командой.
Основные преимущества контейнеризации для PHP-разработчика:
- Единообразие окружений: локальная среда = стейджинг = продакшен. Забудьте про «у меня работает».
- Изоляция зависимостей: проект на PHP 7.4 спокойно соседствует с проектом на PHP 8.3 на одном хост-компьютере.
- Быстрое развёртывание: достаточно запушить образ в registry и обновить контейнер на сервере.
- Масштабируемость: легко добавить ещё один контейнер с PHP-FPM под нагрузкой.
Создаём первый Dockerfile для PHP-приложения
Начнём с самого главного — Dockerfile. Это инструкция по сборке образа вашего приложения. Предположим, у нас есть простое PHP-приложение на Laravel или Symfony (принцип одинаков для любого фреймворка).
# Используем официальный образ PHP 8.2 с FPM
FROM php:8.2-fpm-alpine
# Устанавливаем системные зависимости
RUN apk add --no-cache \
nginx \
supervisor \
libpng-dev \
libjpeg-turbo-dev \
freetype-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) pdo_mysql gd opcache
# Копируем конфиги
COPY ./docker/nginx.conf /etc/nginx/http.d/default.conf
COPY ./docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY ./docker/php.ini /usr/local/etc/php/conf.d/custom.ini
# Устанавливаем Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Копируем исходный код приложения
COPY . /var/www/html
WORKDIR /var/www/html
# Устанавливаем зависимости PHP
RUN composer install --no-dev --optimize-autoloader
# Права доступа
RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
EXPOSE 80
CMD ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
Разбираем по полочкам:
FROM php:8.2-fpm-alpine— берём лёгкий образ на базе Alpine Linux. Он весит ~50 МБ вместо 200+ МБ у десктопных образов.docker-php-ext-install— магическая команда для установки расширений PHP прямо внутри контейнера.COPY --from=composer:latest— мультистейдж-сборка. Мы берём готовый бинарник Composer из официального образа, не устанавливая PHP отдельно.supervisord— менеджер процессов, который будет держать Nginx и PHP-FPM живыми внутри одного контейнера (для простоты). В продакшене лучше разделять сервисы.
Docker Compose: оркестровка нескольких контейнеров
Один контейнер — это круто, но в реальном приложении нужны база данных, кэш и, возможно, очередь. docker-compose.yml позволяет описать всю экосистему в одном файле.
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "80:80"
volumes:
- ./storage:/var/www/html/storage
depends_on:
- db
- redis
environment:
- DB_HOST=db
- REDIS_HOST=redis
db:
image: mysql:8.0
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: app
MYSQL_USER: app
MYSQL_PASSWORD: secret
ports:
- "3306:3306"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
db_data:
Запускаем одной командой: docker-compose up -d. Всё — у вас работает PHP, Nginx, MySQL и Redis. И это воспроизводимо на любой машине, где есть Docker.
Полезные трюки для PHP-разработчика:
- Xdebug в контейнере: добавьте в Dockerfile
pecl install xdebugи настройте remote_host. Никаких больше костылей. - Hot-reload для разработки: используйте volume для монтирования исходников:
.:/var/www/html. Меняете код — изменения сразу видны. - Переменные окружения: выносите настройки БД, API-ключи в
.envи передавайте черезenvironmentв compose-файле.
Оптимизация для продакшена: делаем образ лёгким и безопасным
Контейнеризация PHP приложений для продакшена требует особого подхода. Нельзя просто взять образ для разработки и залить на сервер. Вот несколько обязательных шагов.
1. Мультистейдж-сборка
Собирайте зависимости в одном образе, а копируйте результат в чистый, минимальный образ. Это уменьшает размер в 2-3 раза.
# Этап сборки
FROM composer:2 AS composer
COPY . /app
RUN composer install --no-dev --optimize-autoloader
# Финальный образ
FROM php:8.2-fpm-al