## Зачем 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` - смотреть в реальном времени логи контейнера `api` из докер компос `docker compose down` - остановить контейнере и удалить ## Где лежит учебный проект В репозитории подготовлен полный стек, четыре сервиса: | Путь | Содержимое | | ------------------------------------------- | ---------------------------------------- | | `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 ``` Запуск: ``` docker compose up -d --build ``` Все сервисы подняты Откроем в браузере страницу на порту 8080 и увидим рабочий сервис, отлично. Нам сейчас не интересна логика работы стека, так как не по теме. ## Разбор ключевых фрагментов `docker-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 не пройдёт проверку. ### `expose` vs `ports` - **`ports`** - публикация на хост (нужно для proxy). - **`expose`** - документация + открытие порта **между** контейнерами сети; на сетевой интерфейс хоста не выводится. Так мы не публикуем Postgres наружу - к БД можно попасть только из контейнеров в той же сети (или если вы явно добавите `ports` для отладки). ### Тома ```yaml volumes: pgdata: api_uploads: ``` Именованные тома хранятся в области Docker на диске. Пример «скопировать/сохранить файл в Docker» в runtime: ``` echo hello > /tmp/up.txt docker cp /tmp/up.txt "$(docker compose ps -q api)":/data/uploads/host-demo.txt docker compose exec api ls -la /data/uploads ``` Альтернатива для разработки - **bind-mount** каталога с хоста в сервис (в учебном файле не включено, чтобы не привязывать пути к вашему `$HOME`): ```yaml 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 ``` ## Остановка и очистка Мягко (тома сохраняются): ``` docker compose down ``` Полный сброс демо: ``` docker compose down -v --rmi local ``` ## Документация - [Compose file reference](https://docs.docker.com/compose/compose-file/) - [Networking in Compose](https://docs.docker.com/compose/networking/)