Переход на Docker — это как переезд в новую квартиру: сначала кажется, что всё сложно, но потом понимаешь, что старая мебель больше не нужна. Если вы всё ещё настраиваете PHP-окружение вручную на каждом сервере, эта статья для вас. Мы разберём, как без боли перенести проект в контейнеры и начать жить проще.
Зачем вообще нужен Docker в PHP
Раньше для запуска PHP-проекта нужно было установить Apache или Nginx, PHP с кучей расширений, MySQL, настроить права, прописать конфиги. И всё это на каждой машине разработчика и на сервере. Ошибка в версии расширения — и проект падает. Docker решает эту проблему: вы один раз описываете окружение в файлах и запускаете его где угодно одинаково.
Главные плюсы:
- Изоляция — каждый проект живёт в своём контейнере со своими зависимостями.
- Повторяемость — на локалке, у тестировщика и на проде всё одинаково.
- Быстрый старт — новый разработчик запускает проект одной командой.
- Легкое масштабирование — можно поднять несколько копий приложения.
Но есть и подводные камни: нужно разобраться в Docker, правильно настроить volumes и сеть, а также позаботиться о производительности.
С чего начать: готовим Dockerfile
Первый шаг — создать Dockerfile для вашего PHP-приложения. В нём вы описываете, как собрать образ. Начните с базового образа, например php:8.2-apache. Если используете Nginx + PHP-FPM, то лучше взять php:8.2-fpm и отдельный контейнер для Nginx.
Пример простого Dockerfile для PHP с Apache:
FROM php:8.2-apache
# Устанавливаем расширения
RUN docker-php-ext-install pdo_mysql mysqli
# Копируем код
COPY . /var/www/html/
# Включаем mod_rewrite
RUN a2enmod rewrite
# Права (если нужно)
RUN chown -R www-data:www-data /var/www/html
Этот файл создаёт образ, в котором уже есть PHP 8.2 с Apache и нужными расширениями. Код копируется внутрь. Всё просто.
Но для реального проекта часто нужно больше: Composer, Node.js для сборки фронтенда, xdebug для отладки. Всё это можно добавить в Dockerfile.
php:8.2-fpm-alpine — он легче.
Описываем сервисы в docker-compose
Один контейнер — это скучно. Обычно PHP-проекту нужны база данных, кеш (Redis), возможно, очередь. Для управления несколькими контейнерами используйте docker-compose.yml. Это файл, где вы описываете все сервисы, их связи и настройки.
Пример для типичного проекта на Laravel или Symfony:
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- .:/var/www/html
ports:
- "8080:80"
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: app
MYSQL_USER: user
MYSQL_PASSWORD: secret
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
Здесь два сервиса: app (наш PHP) и db (MySQL). Том db_data сохраняет данные базы между перезапусками. Приложение доступно на порту 8080.
Обратите внимание на volumes — это способ «прокинуть» папку с кодом с хоста в контейнер, чтобы изменения сразу были видны без пересборки. Удобно для разработки.
Настройка окружения и конфигов
В PHP-проектах часто есть файлы конфигурации, которые зависят от окружения: .env, параметры подключения к БД и т.д. В Docker нельзя просто скопировать .env в образ, потому что он может содержать секреты. Лучше передавать переменные окружения через docker-compose.yml или файл .env, который подхватывает Compose.
Например, в docker-compose.yml можно указать:
environment:
APP_ENV: dev
DB_HOST: db
DB_DATABASE: app
DB_USERNAME: user
DB_PASSWORD: secret
А в коде читать эти переменные через getenv() или использовать библиотеку для работы с окружением (например, vlucas/phpdotenv).
Также не забудьте про настройку PHP: может понадобиться увеличить memory_limit или upload_max_filesize. Это делается через кастомный php.ini, который копируется в образ.
docker-compose.override.yml, в котором переопределите порты и смонтируйте папки с кодом. В продакшене используйте только основной docker-compose.yml без монтирования хостовых папок.
Типичные ошибки и как их избежать
При миграции новички часто наступают на одни и те же грабли. Вот самые распространённые:
| Ошибка | Последствия | Решение |
|---|---|---|
| Копирование всего кода в образ без .dockerignore | Образ раздувается, в него попадают логи, кеш, .git | Создайте .dockerignore и исключите лишнее |
| Запуск от root | Потенциальные уязвимости | Создайте пользователя и переключитесь на него в Dockerfile |
| Хранение данных БД внутри контейнера | При перезапуске данные теряются | Используйте volume для /var/lib/mysql |
| Игнорирование кеша Composer | Долгая сборка образа | Используйте многоступенчатую сборку и кеширование слоёв |
Ещё одна частая проблема — права доступа к файлам. Если в контейнере PHP работает от пользователя www-data, а файлы на хосте принадлежат вашему пользователю, могут возникнуть ошибки записи в кеш или логи. Решение: либо выставить одинаковые UID/GID, либо в режиме разработки монтировать папку с нужными правами.
Деплой в продакшен
Когда проект успешно работает локально в Docker, пора переносить его на сервер. Здесь есть несколько подходов:
- Простой: установить Docker на сервер и запустить
docker-compose up -dс продакшен-конфигом. - CI/CD: собирать образ в пайплайне (GitLab CI, GitHub Actions) и пушить в реестр (Docker Hub, GitLab Registry), а на сервере только обновлять контейнеры.
- Оркестрация: использовать Kubernetes или Docker Swarm для управления кластером.
Для небольших проектов достаточно первого варианта. Главное — не забудьте отключить монтирование исходников и использовать собранный образ с кодом внутри. Также настройте логирование: контейнеры должны писать логи в stdout/stderr, а Docker уже позаботится об их сборке.
Пример команды для обновления на сервере:
docker-compose pull
docker-compose up -d --remove-orphans
Если используете собранный образ, то вместо pull будет build или push в зависимости от схемы.
Что в итоге
Миграция PHP-проекта на Docker — это не rocket science, а вполне решаемая задача. Начните с простого Dockerfile, опишите сервисы в docker-compose, настройте окружение и не забудьте про типичные ошибки. В результате вы получите одинаковое окружение везде, быстрый старт для новых разработчиков и упрощённый деплой.
Попробуйте перевести небольшой проект, чтобы набить руку. А когда освоитесь, сможете использовать более продвинутые инструменты вроде Kubernetes. Главное — начать.



