Docker — правила проекта Mart
Краткий контракт: где крутится Docker, что ставим локально, что — нет. Пошаговые команды и troubleshooting добавим позже.
compose.yml— только для server (/srv/mart/src). Локально не поднимаем.
Главное
- Docker на локальной машине не используем и не ставим.
- Docker есть только на удалённом сервере — хост
serverв~/.ssh/config(доступ по SSH-ключу). - Любая команда
docker/docker composeвыполняется на server, не на Mac/Windows разработчика. - Весь dev-стек на server в Docker (frontend, backend, PostgreSQL, кэш) — не через локальный
just front-dev/just back-devкак основной способ запуска.
Отсутствие Docker локально — норма, а не ошибка окружения.
Что где запускаем
| Компонент | Где |
|---|---|
| Frontend (Next.js) | Docker на server |
| Backend (nginx, PHP-FPM, memcached, Redis) | Docker на server |
| PostgreSQL | Docker на server |
Локально: git, IDE, Node/pnpm (линт, typecheck), SSH — без Docker.
На server: весь runtime приложения в контейнерах.
just front-check / just back-check — по-прежнему локально, это проверки кода, не запуск стека.
Именование
У каждого сервиса в compose:
container_nameс префиксомmart-— обязательно
Примеры:mart-nginx,mart-php,mart-front,mart-pg,mart-memcached,mart-redis- Имя сервиса в
compose.yml— тоже с префиксомmart-(единый стиль в командах и логах)
Без префикса mart- новые сервисы не добавляем.
Монтирование: только bind
- Named volumes и секция
volumes:в compose не используем. - Только bind mount: путь на server → путь в контейнере.
- Три типа bind (см. структуру каталогов и пути в контейнере):
/srv/mart/srcна server →/srv/www/mart/currentв контейнере (код);/srv/mart/data/<service>— персистентные данные сервиса;/srv/mart/log/<service>— логи сервиса.
<service> — короткое имя сервиса (обычно без префикса mart-): pg, redis, nginx, php, front, memcached.
Примеры:
| Bind на server | Путь в контейнере | Назначение |
|---|---|---|
/srv/mart/src | /srv/www/mart/current | репозиторий (код) |
/srv/mart/data/pg | каталог данных PostgreSQL | БД |
/srv/mart/log/nginx | /var/log/nginx (или аналог) | access/error log |
Исключений без явного решения в команде не делаем.
SSH
- Единственная точка входа к Docker —
ssh server. - Ключ и параметры хоста — в
~/.ssh/config, в репозиторий не коммитим. - Не настраиваем
DOCKER_HOSTна локальной машине — достаточно SSH.
Структура каталогов на server
Корень окружения Mart на server:
/srv/mart/
├── src/ ← этот репозиторий (git clone)
├── data/
│ ├── pg/ ← данные mart-pg
│ ├── redis/ ← данные mart-redis
│ └── …/ ← data/<service> для каждого сервиса с персистентом
└── log/
├── nginx/ ← логи mart-nginx
├── php/ ← логи mart-php
└── …/ ← log/<service> для каждого сервиса с логами на диске
src— только код и конфиги из git; runtime-данные и логи сюда не пишем.data/<service>— bind для данных (БД, Redis AOF/RDB и т.д.).log/<service>— bind для файлов логов.
docker compose запускаем из /srv/mart/src (compose.yml в корне репозитория).
Пути: server и контейнер
На диске server и внутри контейнеров — разные пути. Якорь в контейнере — /srv/www/mart/current, но содержимое bind у каждого сервиса своё (см. compose.yml):
| Сервис | Bind на server (из /srv/mart/src) | Что видит контейнер в /srv/www/mart/current |
|---|---|---|
mart-nginx | apps/backend/public/ | index.php, bundles/ |
mart-php | apps/backend/ | Symfony-проект (public/, src/, …) |
mart-front | apps/frontend/ | Next.js-проект |
mart-front | docs/ → /srv/www/docs | Markdown для UI /docs (resolveDocsRoot()) |
| Где | Путь | Для чего |
|---|---|---|
| Server (host) | /srv/mart/src | git, rsync, docker compose |
| Логи | /srv/mart/log/<service> | bind в контейнер (например /var/log/nginx) |
| Данные | /srv/mart/data/<service> | Redis, PG и т.д. |
Nginx root — /srv/www/mart/current (public).
FastCGI SCRIPT_FILENAME — /srv/www/mart/current/public/index.php (путь в mart-php, не в nginx).
- Конфиги в
.docker/пишем с учётом таблицы выше. - Скрипты синхронизации работают с host-путём:
/srv/mart/src.
Код на server
- Репозиторий —
/srv/mart/src. - Код должен совпадать с git (pull на server или
bin/server/sync.sh/just bin-server-sync). - Docker-конфиги —
.docker/server/,compose.ymlв git; данные и логи — только в/srv/mart/data/*и/srv/mart/log/*. - Каталоги
/srv/mart/data/*и/srv/mart/log/*на server создаём и бэкапим отдельно от git.
Типичный стек на server
| Сервис (compose) | container_name | Роль |
|---|---|---|
mart-nginx | mart-nginx | HTTP/HTTPS, прокси к PHP и frontend |
mart-php | mart-php | PHP-FPM, Symfony |
mart-front | mart-front | Next.js dev или production-режим |
mart-memcached | mart-memcached | Кэш |
mart-redis | mart-redis | Redis |
mart-pg | mart-pg | PostgreSQL → bind /srv/mart/data/pg |
PHP подключается к БД по имени сервиса в compose (например, mart-pg), не к внешнему db-server.
Структура URL
Точка входа — http://mart.myazin.dev (nginx в mart-nginx, порт 80 на server).
Конфиг — .docker/server/nginx/conf/sites-enabled/mart.myazin.dev.conf.
root nginx: public/ смонтирован в /srv/www/mart/current (см. compose).
Браузер / API-клиент
│
▼
mart-nginx :80 (server_name mart.myazin.dev)
│
├── ^~ /api → @phpApi → mart-php:9001
├── ^~ /bundles/ → disk (статика Swagger UI для /api/docs)
├── /cache → internal (Symfony HTTP cache)
└── / → mart-front:3000 (Next.js: /, /docs, /_next/, …)
Правило: /api — PHP; всё остальное — Next.js. Исключение — /bundles/ (ассеты API Platform, не UI).
Префикс ^~ /api обрабатывается до catch-all location /.
Таблица префиксов
| URL (префикс) | Upstream | Назначение | Примеры |
|---|---|---|---|
/api, /api/… | mart-php:9001 | REST API и OpenAPI | /api, /api/campaigns, /api/docs |
/bundles/ | nginx → disk | Статика API Platform (Swagger) | /bundles/apiplatform/... |
/ (всё остальное) | mart-front:3000 | Next.js | /, /docs/..., /_next/..., /demo/... |
PHP вызывается только через @phpApi → index.php. Прямые запросы к *.php — 404.
Internal: /cache — только для внутренних redirect nginx/Symfony HTTP cache.
Frontend (Next.js)
Маршруты из apps/frontend/src/app/(app)/:
| Путь | Файл | Примечание |
|---|---|---|
/ | (app)/page.tsx | Главная |
/demo/... | (app)/demo/... | Демо UI-кита |
/docs, /docs/... | (app)/docs/... | Документация проекта (Markdown из docs/) |
Frontend обращается к API по /api/... на том же origin.
Backend (Symfony)
| Путь | Конфиг | Примечание |
|---|---|---|
/api/* | api_platform.yaml, prefix /api | CORS на location |
/api/docs, /api/docs.json | API Platform (api_doc) | Swagger UI / OpenAPI |
/bundles/* | assets в public/ | Без PHP |
CORS и ошибки API
.docker/server/nginx/conf/snippets/cors.conf— заголовокMart-Server, preflightOPTIONSна/api/.- Таймаут PHP → JSON 502 / 504 (
@api_error_*в nginx).
Внутренние имена (Docker network)
| Сервис | Порт | Кто обращается |
|---|---|---|
mart-php | 9001 FastCGI | mart-nginx |
mart-front | 3000 HTTP | mart-nginx |
mart-pg | 5432 | mart-php |
mart-redis, mart-memcached | — | mart-php |
Снаружи server — только nginx :80.
Доступ с локальной машины
- Порты слушают на server, не на localhost разработчика.
- Браузер / отладка — SSH-туннель (
ssh -L …). Детали — позже.
DO ✓
- Управлять контейнерами только через
ssh server '… docker compose …'. - Префикс
mart-у всех сервисов иcontainer_name. - Только bind для монтирования; данные и логи — в
/srv/mart/data/<service>и/srv/mart/log/<service>, не вsrc/. - Линт и typecheck — локально (
just front-check,just back-check).
DON'T ✗
- Не ставить Docker Desktop / Engine на рабочую машину «для Mart».
- Не использовать named volumes / anonymous volumes для данных проекта.
- Не писать данные и логи сервисов в
/srv/mart/src— толькоdata/иlog/. - Не поднимать frontend/backend локально как основной dev-стек (если нужен разовый
just front-dev— исключение, не модель проекта). - Не поднимать стек локально через
docker compose(только наserver). - Не считать отсутствие
dockerвbin/check-envпроблемой. - Не хранить секреты и ключи SSH в репозитории.
Что добавим позже
- Сервис
mart-pgвcompose.yml. - Команды: up/down/logs/exec, деплой кода на server.
- SSH-туннели под типичные порты.
- Troubleshooting и
.envдля контейнеров.