0Pricing
PHP Academy · Урок

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-alpine

nginx перед 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 — локальная установка не требуется.

Все уроки этого курса

  1. Контейнеризация PHP-приложения
  2. Многоэтапная сборка и оптимизация
  3. Docker Compose для локальных стеков
  4. CI/CD с GitHub Actions
← Назад к PHP Academy