Главная/Материалы/Материал

compose-stack — практический stack на Docker Compose

Полная система из пяти сервисов: FastAPI, PostgreSQL, Redis, background worker и сервис миграций. Пример собирает вместе всё, что разбиралось в разделах 06–09 курса.

Относится к разделу 09. Docker Compose, урок 9.7. Практический stack.

Быстрый старт

bash
make up        # создаст .env и пароль, соберёт и запустит
curl -s localhost:8000/readyz | python3 -m json.tool
make logs      # логи всех сервисов
make clean     # полный сброс, включая данные

Без make:

bash
cp .env.example .env
head -c 24 /dev/urandom | base64 | tr -d '\n' > secrets/db_password.txt
chmod 600 secrets/db_password.txt
docker compose up -d --build

Файла secrets/db_password.txt в репозитории нет и быть не должно — каталог исключён в .gitignore. Он создаётся локально при первом запуске; без него docker compose up завершится ошибкой secret "db_password" not found, и это правильное поведение: Compose не создаёт молча то, чем не владеет.

Состав

СервисРольСетиПубликуется
apiFastAPI: HTTP-интерфейс, ставит задачи в очередьedge, backendДа (только в dev)
workerРазбирает очередь, пишет результаты в базуbackendНет
migrateОдноразовая задача: схема базыbackendНет
dbPostgreSQL 17backendНет (в dev — на loopback)
cacheRedis 8: очередь задачbackendНет (в dev — на loopback)
toolsОтладочный container, профиль toolsbackendНет

Один образ compose-stack:local обслуживает три роли — api, worker и migrate. Роль задаётся командой в compose.yaml, поэтому код и зависимости у них гарантированно совпадают.

Файлы конфигурации

ФайлКогда применяется
compose.yamlВсегда. Определения сервисов без настроек окружения
compose.override.yamlАвтоматически при docker compose up — окружение разработки
compose.prod.yamlТолько явно: -f compose.yaml -f compose.prod.yaml
bash
docker compose up -d                                        # разработка
docker compose -f compose.yaml -f compose.prod.yaml up -d    # production
docker compose --profile tools up -d                         # плюс отладочный container

Флаг -f отменяет автоматический compose.override.yaml — поэтому production не подхватит локальные настройки разработчика.

Проектные решения

Миграции — отдельный сервис. api и worker зависят от него через condition: service_completed_successfully. Провал миграции не даёт им запуститься вовсе: приложение не увидит базу со старой схемой.

Две сети, backendinternal. У базы и очереди нет маршрута наружу. api состоит в обеих сетях и служит единственным мостом.

Пароль — Compose secret, не переменная окружения. Он приходит файлом в /run/secrets/db_password и не появляется ни в docker inspect, ни в /proc/<pid>/environ. Приложение читает его по соглашению _FILE, как это делают официальные образы.

Liveness не зависит от базы. HEALTHCHECK обращается к /healthz, который знает только о самом процессе. Проверка через /readyz при недоступности базы пометила бы все реплики unhealthy одновременно и вызвала бы лавину перезапусков.

stop_grace_period подобран по длительности работы. У worker — 45 секунд, потому что задача может идти до 30; у базы — 30 секунд на закрытие файлов. Значение по умолчанию в 10 секунд дало бы SIGKILL и код 137.

Worker использует BLMOVE, а не BLPOP. Задача атомарно перемещается в список tasks:processing и не теряется при падении процесса. Обработчик идемпотентен: повторная обработка не создаёт дубликат.

Виртуальное окружение в /opt/venv. Оно вне /app, поэтому bind mount кода в разработке его не скрывает — классическая причина ModuleNotFoundError.

Проверка

bash
./check.sh

Скрипт проверяет девять групп утверждений: порядок миграций, изоляцию сетей, отсутствие пароля в метаданных, работу очереди от постановки до записи в базу, независимость liveness от базы, graceful shutdown worker'а, отличия production-конфигурации и работу профиля. Возвращает ненулевой код при любом расхождении.

Тесты

bash
make test          # прогон в стадии сборки, без кэша
python3 -m pytest tests/ -q    # локально

Unit-тесты покрывают разбор конфигурации, формирование DSN и чтение секретов — всё, что проверяемо без поднятых сервисов. Проверка взаимодействия сервисов относится к integration-тестам и выполняется скриптом check.sh.

Что осталось за рамками

  • Reverse proxy. В production api слушает без публикации портов; предполагается, что трафик пускает внешний прокси.
  • Управление секретами. Compose secret вне Swarm — это bind mount обычного файла: на диске host пароль лежит открытым текстом. Ротация требует пересоздания container'а.
  • Резервное копирование. Volume db-data переживает docker compose down, но не down -v. Схема копирования — в уроке 7.6.
  • Ограничение числа повторов задачи. Задача, падающая всегда, будет возвращаться в очередь бесконечно. В production нужна очередь «мёртвых» задач.

Требуемые версии

КомпонентВерсия
Docker Engine28.x или 29.x
Docker Composev2 (плагин)
Образыpython:3.13-slim, postgres:17-alpine, redis:8-alpine

Навигация

← Все примеры · Урок 9.7 · Раздел 09

Markdown на GitHub ↗