9.0 KiB
Зачем Docker Compose
Когда сервисов несколько (БД, бэкенд, фронт, прокси), писать длинные docker run неудобно. Compose описывает весь стек в одном файле (compose.yaml или docker-compose.yml), поднимает общую сеть и тома, учитывает порядок старта через depends_on и проверки healthcheck.
Команды:
docker compose up -d --build
docker compose ps
docker compose logs -f api
docker compose down
docker compose down -v
Последняя команда с -v удалит именованные тома — данные БД пропадут (удобно для сброса демо, опасно если это прод).
Где лежит учебный проект
В репозитории подготовлен полный стек (четыре сервиса):
| Путь | Содержимое |
|---|---|
docker/examples/multi-service/compose.yaml |
Описание всех сервисов, сетей, томов |
docker/examples/multi-service/.env.example |
Пример переменных окружения для Compose |
docker/examples/multi-service/web/ |
Nginx + статика через COPY |
docker/examples/multi-service/api/ |
Flask + Postgres + загрузка файлов в том |
docker/examples/multi-service/proxy/ |
Входной nginx: / → web, /api/ → api |
Скопируйте переменные окружения:
cd docker/examples/multi-service
cp .env.example .env
Скриншот: файловый менеджер или IDE с деревом папок multi-service (видны compose.yaml, web, api, proxy).
Запуск:
docker compose up -d --build
Скриншот: вывод docker compose up — этапы build, Creating..., Started.
Скриншот: docker compose ps — все сервисы running (или healthy где настроено).
Откройте в браузере http://127.0.0.1:8080 (если в .env не меняли HTTP_PORT).
Скриншот: главная страница демо со ссылками на API.
Проверка API через прокси:
curl -s http://127.0.0.1:8080/api/health | jq .
curl -s http://127.0.0.1:8080/api/notes | jq .
curl -s -X POST http://127.0.0.1:8080/api/notes \
-H 'Content-Type: application/json' \
-d '{"body":"Первая заметка из curl"}' | jq .
echo demo > /tmp/upload-demo.txt
curl -s -F "file=@/tmp/upload-demo.txt" http://127.0.0.1:8080/api/upload | jq .
curl -s http://127.0.0.1:8080/api/uploads | jq .
Скриншот: терминал с ответами JSON.
Логическая схема стека
- Пользователь хоста подключается только к proxy (порт
HTTP_PORT). - proxy по пути
/отдаёт статику с web; по/api/— api (внутренний URL без префикса/api). - api ходит в db по hostname
dbи порту5432(стандарт Postgres) — резолвится DNS-ом Docker в той же сетиbackend. - Данные БД — в томе
pgdata; загруженные файлы API — в томеapi_uploads.
Скриншот: нарисованная схема стрелок browser → proxy → web/api → db; подписать тома.
Разбор ключевых фрагментов compose.yaml
Имена и сеть
Поле name: multi-service-demo задаёт префикс для имён контейнеров/ресурсов по умолчанию (удобно не конфликтовать с другими проектами).
Сеть backend с драйвером bridge — все перечисленные сервисы в одной L2-сети, видят друг друга по DNS-имени сервиса (db, api, web, proxy).
Зависимости и здоровье
depends_on:
db:
condition: service_healthy
Без condition Compose лишь упорядочивает старт, но не ждёт готовности БД. С healthcheck у db сервис api не начнёт считаться поднятым для зависимых, пока Postgres не пройдёт проверку.
Скриншот: docker compose logs db в момент database system is ready to accept connections.
expose vs ports
ports— публикация на хост (нужно для proxy).expose— документация + открытие порта между контейнерами сети; на сетевой интерфейс хоста не выводится.
Так мы не публикуем Postgres наружу — к БД можно попасть только из контейнеров в той же сети (или если вы явно добавите ports для отладки).
Тома
volumes:
pgdata:
api_uploads:
Именованные тома хранятся в области Docker на диске. Пример «скопировать/сохранить файл в Docker» в runtime:
echo hello > /tmp/up.txt
# имя контейнера смотрите в выводе: docker compose ps -q api
docker cp /tmp/up.txt "$(docker compose ps -q api)":/data/uploads/host-demo.txt
docker compose exec api ls -la /data/uploads
Скриншот: список файлов в /data/uploads внутри контейнера api.
Альтернатива для разработки — bind-mount каталога с хоста в сервис (в учебном файле не включено, чтобы не привязывать пути к вашему $HOME):
services:
api:
volumes:
- ./local_uploads:/data/uploads
Копирование файлов в контейнер в контексте Compose
| Способ | Когда использовать |
|---|---|
COPY в Dockerfile |
Статика, код, конфиги, которые должны быть в образе на момент деплоя |
| Именованный / bind том | Данные, логи, загрузки пользователей, меняющиеся без пересборки |
docker cp |
Разовая отладка, экстренная подмена файла |
Обновление одного сервиса после правки кода
# изменили только api/app.py
docker compose build api
docker compose up -d api
Скриншот: пересборка только слоя COPY app.py (кэш BuildKit для предыдущих шагов).
Просмотр конфигурации, которую «увидел» Compose
docker compose config
Скриншот: полный YAML после подстановки .env (проверьте порты и пароли перед скрином — размыть секреты).
Остановка и очистка
Мягко (тома сохраняются):
docker compose down
Полный сброс демо:
docker compose down -v --rmi local
Скриншот: docker volume ls без томов проекта после down -v.
Идеи для дополнительных скриншотов (по желанию)
- Portainer или Docker Desktop — список контейнеров и томов в GUI.
docker compose top— процессы внутри сервисов.- Ошибка неверного
depends_on/ healthcheck — учебный кадр «как выглядит», если api стартует раньше БД безcondition.
Документация
- Compose file reference
- Networking in Compose
- Use Compose Watch — live reload при разработке (отдельная тема)