Docker и PHP: контейнеризация приложений продвинутого уровня
Контейнеризация с помощью Docker давно стала стандартом для разработки и развертывания PHP-приложений. Базовые знания — запустить контейнер с PHP и Nginx — это лишь первый шаг. На продвинутом уровне требуется настройка многоэтапной сборки, оптимизация размера образов, работа с несколькими сервисами, управление переменными окружения, интеграция с CI/CD и построение микросервисной архитектуры. В этой статье мы разберем ключевые техники, которые помогут вам вывести контейнеризацию PHP на новый уровень.
1. Многоэтапная сборка (Multi-stage builds) для PHP
Многоэтапная сборка позволяет использовать несколько FROM инструкций в одном Dockerfile. Это идеально подходит для PHP-приложений, где на этапе сборки нужны Composer, Node.js и другие инструменты, а в финальный образ должны попасть только скомпилированные файлы и минимальный набор зависимостей.
Пример Dockerfile для Laravel-приложения с многоэтапной сборкой:
# Этап 1: Установка зависимостей и сборка
FROM composer:2.5 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-interaction
FROM node:18 AS frontend
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production
COPY resources/ ./resources/
RUN npm run production
# Этап 2: Финальный образ
FROM php:8.2-fpm-alpine3.18 AS final
WORKDIR /var/www/html
# Установка необходимых PHP-расширений
RUN apk add --no-cache \
libpng-dev \
libjpeg-turbo-dev \
freetype-dev \
libzip-dev \
oniguruma-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql \
mbstring \
gd \
zip \
opcache
# Копирование только необходимых файлов из предыдущих этапов
COPY --from=vendor /app/vendor/ ./vendor/
COPY --from=frontend /app/public/build/ ./public/build/
COPY . .
# Оптимизация для продакшена
RUN php artisan optimize
EXPOSE 9000
CMD ["php-fpm"]
Ключевые преимущества:
- Финальный образ содержит только runtime-зависимости (PHP-FPM, расширения, код).
- Инструменты сборки (Composer, Node.js) не попадают в продакшен.
- Значительное уменьшение размера образа (с 800-900 MB до 150-200 MB).
2. Оптимизация размера Docker-образов для PHP
Маленькие образы быстрее загружаются, требуют меньше места на диске и снижают поверхность атаки. Основные стратегии:
- Используйте alpine-версии базовых образов.
php:8.2-fpm-alpineвесит ~50 MB против ~400 MB для стандартногоphp:8.2-fpm. - Минимизируйте количество слоев. Объединяйте команды
RUNс помощью&&. - Удаляйте временные файлы. После установки расширений чистите кеш:
docker-php-source deleteиapk del .build-deps. - Используйте
.dockerignore. Исключите.git,node_modules,tests,.envи другие ненужные файлы.
Пример продвинутого .dockerignore:
.git
.gitignore
.env
.env.example
node_modules
tests
storage/logs/*
!storage/logs/.gitkeep
docker-compose.yml
Makefile
README.md
3. Docker Compose для сложных PHP-проектов
Для приложений на PHP, использующих базы данных, очереди, кеш и веб-сервер, docker-compose.yml становится центральным файлом конфигурации. Продвинутые настройки включают:
- Сети (networks): изолируйте сервисы (например, база данных не должна быть доступна извне).
- Тома (volumes): используйте именованные тома для данных БД и анонимные тома для кода в разработке.
- Healthchecks: проверяйте, что сервисы готовы к работе.
- Переменные окружения: используйте
.envфайл иenv_file.
Пример расширенного docker-compose.yml для Symfony-проекта:
version: '3.8'
services:
php:
build:
context: .
target: final
container_name: app_php
volumes:
- ./:/var/www/html:delegated
networks:
- app-network
environment:
- APP_ENV=prod
- DATABASE_URL=postgresql://user:pass@db:5432/app?serverVersion=15
depends_on:
db:
condition: service_healthy
nginx:
image: nginx:1.25-alpine
container_name: app_nginx
ports:
- "8080:80"
volumes:
- ./:/var/www/html:ro
- ./docker/nginx/conf.d:/etc/nginx/conf.d:ro
networks:
- app-network
depends_on:
- php
db:
image: postgres:15-alpine
container_name: app_db
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- app-network
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: app
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d app"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: app_redis
networks:
- app-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
networks:
app-network:
driver: bridge
volumes:
pgdata:
4. Интеграция с CI/CD и микросервисами на PHP
В продакшене Docker-образы должны собираться автоматически. Для PHP-проектов популярны GitHub Actions, GitLab CI и Jenkins. Пример пайплайна для сборки и публикации образа на PHP:
# .github/workflows