Files
docker/docs/4. Docker Compose — несколько сервисов, сеть, тома.md
T
2026-05-04 11:07:31 +03:00

9.0 KiB
Raw Blame History

Зачем 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.


Логическая схема стека

  1. Пользователь хоста подключается только к proxy (порт HTTP_PORT).
  2. proxy по пути / отдаёт статику с web; по /api/api (внутренний URL без префикса /api).
  3. api ходит в db по hostname db и порту 5432 (стандарт Postgres) — резолвится DNS-ом Docker в той же сети backend.
  4. Данные БД — в томе 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.

Документация