Docker Compose для локальных стеков
Запускайте PHP, базу данных и кэш вместе локально
«Docker Compose для локальных стеков» — бесплатный урок PHP Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения PHP Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс PHP Academy содержит 4 уроков всего.
Локальные стеки с Compose
Настоящие приложения PHP никогда не состоят только из PHP — им нужны база данных, кэш, а иногда очередь и перехватчик почты. Docker Compose объявляет всё это как сервисы в одном файле и подключает их к общей сети, чтобы они могли обращаться друг к другу по имени.
На этом уроке мы соберём полный локальный стек: PHP-FPM + nginx + MySQL + Redis, с томами, проверками работоспособности и упорядочиванием зависимостей.
Каркас сервиса
Файл Compose перечисляет сервисы внутри services:. Каждый сервис может собрать образ из Dockerfile с помощью build или загрузить его с помощью image. Compose создаёт сеть по умолчанию, в которой каждый сервис доступен по своему ключу: ваше приложение PHP подключается к MySQL по адресу хоста db, а не localhost.
services:
app:
build:
context: .
target: dev # multi-stage dev target
volumes:
- ./:/app # live code mount
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.4
redis:
image: redis:7-alpinenginx перед FPM
FPM использует FastCGI через порт 9000, а не HTTP. nginx принимает HTTP-запросы и передаёт запросы к .php на app:9000. Конфигурация nginx обращается к сервису PHP по его имени в Compose.
# docker/nginx/default.conf
server {
listen 80;
root /app/public;
index index.php;
location / {
try_files $uri /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000; # service name from compose
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}Подключение веб-сервиса
Сервис nginx подключает тот же исходный код (чтобы определить SCRIPT_FILENAME) и конфигурацию, открывает порт 80 и зависит от приложения. Оба сервиса используют /app, поэтому пути совпадают по обе стороны FastCGI.
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
volumes:
- ./:/app:ro
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- appПостоянные тома
Файловые системы контейнеров непостоянны. Именованные тома сохраняют файлы базы данных после выполнения docker compose down. Монтирование каталогов (./:/app) синхронизирует код с хоста в реальном времени для разработки. Используйте именованные тома для данных с состоянием, а монтирование каталогов — для исходного кода.
services:
db:
image: mysql:8.4
environment:
MYSQL_DATABASE: app
MYSQL_USER: app
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: rootsecret
volumes:
- dbdata:/var/lib/mysql
volumes:
dbdata: # survives `down`, removed only by `down -v`Проверки работоспособности и зависимости
Одного depends_on недостаточно: он ждёт только запуска контейнера, а не готовности MySQL принимать подключения. Добавьте healthcheck и используйте condition: service_healthy, чтобы приложение ждало фактической готовности базы данных.
services:
db:
image: mysql:8.4
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-prootsecret"]
interval: 5s
timeout: 3s
retries: 10
app:
build: .
depends_on:
db:
condition: service_healthy # waits for healthcheck passОкружение и .env
Compose автоматически загружает соседний файл .env для подстановки переменных, а конфигурацию приложения можно передать через environment или env_file. Не храните секреты в зафиксированном файле Compose; вместо этого ссылайтесь на переменные.
services:
app:
build: .
env_file:
- .env
environment:
DATABASE_URL: "mysql://app:secret@db:3306/app"
REDIS_URL: "redis://redis:6379"
# .env (gitignored) provides ${...} substitutions
# MYSQL_PASSWORD=secretПодключение из PHP
Внутри сети имена хостов совпадают с именами сервисов. Ваш код PHP напрямую подключается к db и redis. Этот фрагмент разбирает DSN так, как это сделал бы слой конфигурации, и показывает, как имя сервиса Compose попадает в строку подключения.
<?php
$dsn = 'mysql://app:secret@db:3306/app';
$p = parse_url($dsn);
printf("driver: %s\n", $p['scheme']);
printf("host: %s\n", $p['host']); // 'db' resolves via compose DNS
printf("port: %d\n", $p['port']);
printf("db: %s\n", ltrim($p['path'], '/'));
$pdoDsn = sprintf('mysql:host=%s;port=%d;dbname=%s', $p['host'], $p['port'], ltrim($p['path'], '/'));
echo $pdoDsn . PHP_EOL;
?>Xdebug для локальной разработки
Подключайте конфигурацию Xdebug только локально (через цель сборки dev). Укажите в client_host значение host.docker.internal, чтобы отладчик мог обратиться к вашей среде разработки на хосте. Никогда не отправляйте Xdebug в рабочую среду — он резко снижает производительность.
; docker/php/xdebug.ini (mounted only in dev)
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003Запуск разовых команд
docker compose run запускает временный контейнер для миграций, тестов или Composer, а exec выполняет команду внутри уже работающего сервиса. Используйте run --rm для таких задач, чтобы временный контейнер удалялся после завершения.
# Run migrations against the running db
docker compose exec app php bin/console doctrine:migrations:migrate
# One-off: install deps without a long-lived container
docker compose run --rm app composer install
# Tail logs of just the web service
docker compose logs -f webФайлы переопределения
Compose автоматически объединяет docker-compose.yml с docker-compose.override.yml. Храните в основном файле значения по умолчанию, соответствующие рабочей среде, а тома, порты и Xdebug, нужные только для разработки, помещайте в файл переопределения — тогда CI использует основной файл, а разработчики бесплатно получают дополнительные настройки.
# docker-compose.override.yml (auto-merged, dev only)
services:
app:
volumes:
- ./docker/php/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini:ro
environment:
APP_ENV: dev
# CI runs: docker compose -f docker-compose.yml up (no override)Быстрая проверка
Почему простого depends_on: [db] недостаточно перед запуском миграций?
Итоги
Вы собрали локальный стек с Compose: PHP-FPM за nginx (FastCGI на app:9000), MySQL и Redis, доступные по именам сервисов, именованные тома для сохранения данных, проверки работоспособности, управляющие depends_on, конфигурацию через переменные окружения, Xdebug в переопределении только для разработки и разовые команды через run/exec.
Помните: имена сервисов являются именами хостов DNS, файлы переопределения не позволяют дополнительным настройкам разработки попасть в CI, а проверки работоспособности надёжнее простого порядка запуска.
Часто задаваемые вопросы
Урок «Docker Compose для локальных стеков» бесплатный?
Да — полный текст урока «Docker Compose для локальных стеков» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс PHP Academy, подпишись на CoddyKit PRO. Курс PHP Academy содержит 4 уроков всего.
Чему я научусь в уроке «Docker Compose для локальных стеков»?
Запускайте PHP, базу данных и кэш вместе локально Ты практикуешь PHP Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать PHP Academy?
Предыдущий опыт не требуется. PHP Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Docker Compose для локальных стеков»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке PHP Academy?
Да. Каждый урок PHP Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Контейнеризация PHP-приложения
- Многоэтапная сборка и оптимизация
- Docker Compose для локальных стеков
- CI/CD с GitHub Actions